mod err;
mod sctx;
pub(crate) mod wctx;
use std::{sync::Arc, task::Waker};
use parking_lot::{Condvar, Mutex};
pub use sctx::SetCtx;
pub use wctx::{WaitCtx, WaitFuture};
pub use err::Error;
enum State<T, S, E> {
Waiting,
Data(T),
Finalized,
Err(Error<S, E>)
}
struct Inner<T, S, E> {
state: State<T, S, E>,
sctx_state: S,
waker: Option<Waker>,
wctx_dropped: bool
}
impl<T, S, E> Inner<T, S, E> {
fn try_get(&mut self) -> Result<Option<T>, Error<S, E>> {
match self.state {
State::Waiting => Ok(None),
State::Data(_) => {
let old = std::mem::replace(&mut self.state, State::Finalized);
let State::Data(data) = old else {
panic!("Unable to extract data");
};
Ok(Some(data))
}
State::Err(_) => {
let old = std::mem::replace(&mut self.state, State::Finalized);
let State::Err(err) = old else {
panic!("Unable to extract error");
};
Err(err)
}
State::Finalized => {
unimplemented!("Unexpected state");
}
}
}
}
struct Shared<T, S, E> {
inner: Mutex<Inner<T, S, E>>,
signal: Condvar
}
impl<T, S, E> Shared<T, S, E> {
fn notify_waiter(&self, inner: &mut Inner<T, S, E>) {
self.signal.notify_one();
if let Some(waker) = inner.waker.take() {
waker.wake();
}
}
}
#[must_use]
pub fn mkpair<T, S, E>() -> (SetCtx<T, S, E>, WaitCtx<T, S, E>)
where
S: Clone + Default
{
let inner = Inner {
state: State::Waiting,
sctx_state: S::default(),
waker: None,
wctx_dropped: false
};
let sh = Shared {
inner: Mutex::new(inner),
signal: Condvar::new()
};
let sh = Arc::new(sh);
let sctx = SetCtx(Arc::clone(&sh));
let wctx = WaitCtx(sh);
(sctx, wctx)
}