mirror of https://github.com/Trivernis/vented.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
4.8 KiB
Rust
176 lines
4.8 KiB
Rust
/*
|
|
* vented asynchronous event based tcp server
|
|
* Copyright (C) 2020 trivernis
|
|
* See LICENSE for more information
|
|
*/
|
|
|
|
use std::mem;
|
|
use std::sync::Arc;
|
|
use std::time::{Duration, Instant};
|
|
|
|
use parking_lot::Mutex;
|
|
|
|
use crate::WaitGroup;
|
|
|
|
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 asynchronously
|
|
pub async fn get_value_async(&mut self) -> Result<V, E> {
|
|
while self.value.lock().is_none() {
|
|
async_std::task::sleep(Duration::from_millis(1)).await;
|
|
}
|
|
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>> {
|
|
async_std::task::block_on(self.get_value_with_timeout_async(timeout))
|
|
}
|
|
|
|
/// Returns the value of the future asynchronous with a timeout after the given duration
|
|
pub async fn get_value_with_timeout_async(
|
|
&mut self,
|
|
timeout: Duration,
|
|
) -> Option<Result<V, E>> {
|
|
let start = Instant::now();
|
|
|
|
while self.value.lock().is_none() {
|
|
async_std::task::sleep(Duration::from_millis(1)).await;
|
|
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),
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<T, E> Sync for AsyncValue<T, E> {}
|
|
unsafe impl<T, E> Send for AsyncValue<T, E> {}
|