1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! A [`Future`] value that resolves once it's explicitly completed, potentially
//! from a different thread or task, similar to Java's [`ControlledFuture`].
//!
//! Currently, this is implemented using [`Mutex`][parking_lot::Mutex] from the [`parking_lot`] crate.
//!
//! # Examples
//!
//! Create an incomplete [`ControlledFuture`] and explicitly complete it with the
//! completer:
//! ```
//! # use future_clicker::ControlledFuture;
//! # use futures::executor::block_on;
//! let (future, completer) = ControlledFuture::<i32>::new();
//! completer.complete(5).unwrap();
//! assert_eq!(block_on(future), Ok(5));
//! ```
//!
//! Create an initially complete [`ControlledFuture`] that can be immediately
//! resolved:
//! ```
//! # use future_clicker::ControlledFuture;
//! # use futures::executor::block_on;
//! assert_eq!(block_on(ControlledFuture::new_completed(10)), Ok(10));
//! ```

#![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},
};

/// A [`Future`] that will resolve either immediately, or in the future.
///
/// Will not resolve unless it has been explicitly completed, either
/// by constructing it with [`ControlledFuture::new_completed`], or using [`FutureClicker::complete`].
#[derive(Debug)]
pub struct ControlledFuture<T: Unpin> {
    state: Arc<Mutex<State<T>>>,
}

impl<T: Unpin + Send + 'static> ControlledFuture<T> {
    /// Construct a `ControlledFuture` that will resolve once the returned
    /// `FutureClicker` is used to set a value.
    #[must_use]
    pub fn new() -> (Self, FutureClicker<T>) {
        let s = State::new();
        (Self { state: s.0 }, FutureClicker { state: s.1 })
    }

    /// Construct a [`ControlledFuture`] that will resolve immediately to the
    /// given value.
    ///
    /// No [`FutureClicker`] is returned as the [`ControlledFuture`] is already complete.
    #[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))
            }
        }
    }
}