#![warn(clippy::pedantic, missing_docs)]
mod completer;
mod error;
mod state;
use std::{
future::Future,
marker::Unpin,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use parking_lot::Mutex;
use tracing::{instrument, trace};
use self::state::State;
pub use self::{
completer::FutureClicker,
error::{Error, Result},
};
#[derive(Debug)]
pub struct ControlledFuture<T: Unpin> {
state: Arc<Mutex<State<T>>>,
}
impl<T: Unpin + Send + 'static> ControlledFuture<T> {
#[must_use]
pub fn new() -> (Self, FutureClicker<T>) {
let s = State::new();
(Self { state: s.0 }, FutureClicker { state: s.1 })
}
#[must_use]
pub fn new_completed(value: T) -> Self {
Self {
state: State::new_completed(value),
}
}
}
impl<T: Unpin + 'static + Send> Future for ControlledFuture<T> {
type Output = Result<T>;
#[instrument(skip_all)]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
use Poll::{Pending, Ready};
use State::{Complete, Dropped, Incomplete, Waiting};
trace!("poll");
let mut state = self.state.lock_arc();
trace!("locked");
match &mut *state {
Waiting(w) if w.will_wake(cx.waker()) => {
trace!("state Waiting will_wake");
Pending
}
state @ (Waiting(_) | Incomplete) => {
trace!("state {state:?}");
*state = Waiting(cx.waker().clone());
Pending
}
Complete(value) => {
if let Some(value) = value.take() {
trace!("state Complete Some");
Ready(Ok(value))
} else {
trace!("state Complete None");
Ready(Err(Error::AlreadyCompleted))
}
}
Dropped => {
trace!("state Dropped");
Ready(Err(Error::CompleterDropped))
}
}
}
}