use std::{
fmt::{self, Debug, Formatter},
sync::{
atomic::{AtomicBool, Ordering::SeqCst},
Arc, Condvar, Mutex,
},
time::Duration,
};
pub struct Future<T> {
signal: Condvar,
result: Mutex<Option<T>>,
}
impl<T> Future<T> {
pub fn new() -> Self {
Self { signal: Condvar::new(), result: Mutex::default() }
}
}
impl<T> Debug for Future<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let result: &dyn Debug = match self.result.lock() {
Ok(result) if result.is_some() => &Some("<opaque>"),
Ok(_) => &Option::<&str>::None,
Err(_) => &"<poisoned>",
};
f.debug_struct("Future").field("signal", &"<opaque>").field("result", &result).finish()
}
}
pub struct Setter<T> {
future: Arc<Future<T>>,
cancelled: Arc<AtomicBool>,
}
impl<T> Setter<T> {
pub(in crate) const fn new(future: Arc<Future<T>>, cancelled: Arc<AtomicBool>) -> Self {
Self { future, cancelled }
}
pub fn is_cancelled(&self) -> bool {
self.cancelled.load(SeqCst)
}
pub fn cancel(&self) {
self.cancelled.store(true, SeqCst);
self.future.signal.notify_all();
}
pub fn set(self, value: T) {
if !self.is_cancelled() {
let mut result = self.future.result.lock().expect("The future is poisoned?!");
*result = Some(value);
self.future.signal.notify_all();
}
}
}
impl<T> Debug for Setter<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Setter").field("future", &self.future).field("cancelled", &self.cancelled.load(SeqCst)).finish()
}
}
impl<T> Drop for Setter<T> {
fn drop(&mut self) {
self.cancel();
}
}
pub struct Getter<T> {
future: Arc<Future<T>>,
cancelled: Arc<AtomicBool>,
}
impl<T> Getter<T> {
pub(in crate) const fn new(future: Arc<Future<T>>, cancelled: Arc<AtomicBool>) -> Self {
Self { future, cancelled }
}
pub fn is_cancelled(&self) -> bool {
self.cancelled.load(SeqCst)
}
pub fn cancel(&self) {
self.cancelled.store(true, SeqCst);
}
pub fn wait(self) -> Option<T> {
let cond = |result: &mut Option<T>| result.is_none() && !self.is_cancelled();
let result = self.future.result.lock().expect("The future is poisoned?!");
let mut result = self.future.signal.wait_while(result, cond).expect("The future is poisoned?!");
result.take()
}
pub fn wait_timeout(self, timeout: Duration) -> Result<Option<T>, Self> {
let cond = |queue: &mut Option<T>| queue.is_none() && !self.is_cancelled();
let result = self.future.result.lock().expect("The future is poisoned?!");
let (mut result, timeout_result) =
self.future.signal.wait_timeout_while(result, timeout, cond).expect("The future is poisoned?!");
if timeout_result.timed_out() {
drop(result);
return Err(self);
}
Ok(result.take())
}
}
impl<T> Debug for Getter<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Getter").field("future", &self.future).field("cancelled", &self.cancelled.load(SeqCst)).finish()
}
}
impl<T> Drop for Getter<T> {
fn drop(&mut self) {
self.cancel();
}
}