mirror of https://github.com/Trivernis/vented.git
Add error and success callback to AsyncValue
Signed-off-by: trivernis <trivernis@protonmail.com>pull/1/head
parent
d3d6d0baaf
commit
9137eeb673
@ -1,7 +1,7 @@
|
||||
pub mod crypto;
|
||||
pub mod event;
|
||||
pub mod event_handler;
|
||||
pub mod result;
|
||||
pub mod server;
|
||||
pub mod utils;
|
||||
|
||||
pub use crossbeam_utils::sync::WaitGroup;
|
||||
|
@ -0,0 +1,2 @@
|
||||
pub mod result;
|
||||
pub mod sync;
|
@ -0,0 +1,144 @@
|
||||
use crate::WaitGroup;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{mem, thread};
|
||||
|
||||
pub struct AsyncValue<V, E> {
|
||||
value: Arc<Mutex<Option<V>>>,
|
||||
error: Arc<Mutex<Option<E>>>,
|
||||
wg: Option<WaitGroup>,
|
||||
err_cb: Arc<Mutex<Option<Box<dyn FnOnce(&E) -> () + Send + Sync>>>>,
|
||||
ok_cb: Arc<Mutex<Option<Box<dyn FnOnce(&V) -> () + Send + Sync>>>>,
|
||||
}
|
||||
|
||||
impl<V, E> AsyncValue<V, E>
|
||||
where
|
||||
E: std::fmt::Display,
|
||||
{
|
||||
/// Creates the future with no value
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
value: Arc::new(Mutex::new(None)),
|
||||
error: Arc::new(Mutex::new(None)),
|
||||
wg: Some(WaitGroup::new()),
|
||||
err_cb: Arc::new(Mutex::new(None)),
|
||||
ok_cb: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new AsyncValue with an already resolved value
|
||||
pub fn with_value(value: V) -> Self {
|
||||
Self {
|
||||
value: Arc::new(Mutex::new(Some(value))),
|
||||
error: Arc::new(Mutex::new(None)),
|
||||
wg: None,
|
||||
err_cb: Arc::new(Mutex::new(None)),
|
||||
ok_cb: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_error(error: E) -> Self {
|
||||
Self {
|
||||
value: Arc::new(Mutex::new(None)),
|
||||
error: Arc::new(Mutex::new(Some(error))),
|
||||
wg: None,
|
||||
err_cb: Arc::new(Mutex::new(None)),
|
||||
ok_cb: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_error<F>(&mut self, cb: F) -> &mut Self
|
||||
where
|
||||
F: FnOnce(&E) -> () + Send + Sync + 'static,
|
||||
{
|
||||
self.err_cb.lock().replace(Box::new(cb));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_success<F>(&mut self, cb: F) -> &mut Self
|
||||
where
|
||||
F: FnOnce(&V) -> () + Send + Sync + 'static,
|
||||
{
|
||||
self.ok_cb.lock().replace(Box::new(cb));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the value of the future consuming the wait group
|
||||
pub fn resolve(&mut self, value: V) {
|
||||
if let Some(cb) = self.ok_cb.lock().take() {
|
||||
cb(&value)
|
||||
}
|
||||
self.value.lock().replace(value);
|
||||
mem::take(&mut self.wg);
|
||||
}
|
||||
|
||||
/// Sets an error for the value
|
||||
pub fn reject(&mut self, error: E) {
|
||||
if let Some(cb) = self.err_cb.lock().take() {
|
||||
cb(&error)
|
||||
}
|
||||
self.error.lock().replace(error);
|
||||
mem::take(&mut self.wg);
|
||||
}
|
||||
|
||||
pub fn result(&mut self, result: Result<V, E>) {
|
||||
match result {
|
||||
Ok(v) => self.resolve(v),
|
||||
Err(e) => self.reject(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_unwrap(&mut self) -> V {
|
||||
match self.get_value() {
|
||||
Ok(v) => v,
|
||||
Err(e) => panic!("Unwrap on Err value: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value of the future after it has been set.
|
||||
/// This call blocks
|
||||
pub fn get_value(&mut self) -> Result<V, E> {
|
||||
if let Some(wg) = mem::take(&mut self.wg) {
|
||||
wg.wait();
|
||||
}
|
||||
if let Some(err) = self.error.lock().take() {
|
||||
Err(err)
|
||||
} else {
|
||||
Ok(self.value.lock().take().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value of the future only blocking for the given timeout
|
||||
pub fn get_value_with_timeout(&mut self, timeout: Duration) -> Option<Result<V, E>> {
|
||||
let start = Instant::now();
|
||||
|
||||
while self.value.lock().is_none() {
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
if start.elapsed() > timeout {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(err) = self.error.lock().take() {
|
||||
Some(Err(err))
|
||||
} else if let Some(value) = self.value.lock().take() {
|
||||
Some(Ok(value))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Clone for AsyncValue<T, E> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
value: Arc::clone(&self.value),
|
||||
error: Arc::clone(&self.error),
|
||||
wg: self.wg.clone(),
|
||||
err_cb: Arc::clone(&self.err_cb),
|
||||
ok_cb: Arc::clone(&self.ok_cb),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue