future_clicker/
completer.rs

1use std::{mem, sync::Arc};
2
3use parking_lot::Mutex;
4use tracing::{instrument, trace};
5
6use crate::{state::State, Error, Result};
7
8/// Used to complete a [`ControlledFuture`][crate::ControlledFuture] so it may resolve to the given value.
9///
10/// Dropping a [`FutureClicker`] without calling [`FutureClicker::complete`] will
11/// cause the [`ControlledFuture`][crate::ControlledFuture] to panic.
12#[derive(Debug)]
13#[allow(clippy::module_name_repetitions)]
14pub struct FutureClicker<T: Unpin + Send + 'static> {
15    pub(crate) state: Arc<Mutex<State<T>>>,
16}
17
18impl<T: Unpin + Send + 'static> FutureClicker<T> {
19    /// Complete the associated [`ControlledFuture`][crate::ControlledFuture].
20    ///
21    /// # Errors
22    /// - [`Error::AlreadyCompleted`] - The [`ControlledFuture`][crate::ControlledFuture] future is already resolved.
23    /// - [`Error::CompleterDropped`] - The [`FutureClicker`] has already been dropped.
24    #[instrument(skip_all)]
25    pub fn complete(self, value: T) -> Result<()> {
26        use State::{Complete, Dropped, Incomplete, Waiting};
27
28        trace!("complete");
29
30        let mut state = self.state.lock_arc();
31
32        trace!("have lock");
33
34        match mem::replace(&mut *state, State::Complete(Some(value))) {
35            Incomplete => Ok(()),
36            Waiting(waker) => {
37                waker.wake();
38                Ok(())
39            }
40            old @ Complete(_) => {
41                *state = old;
42                Err(Error::AlreadyCompleted)
43            }
44            old @ Dropped => {
45                *state = old;
46                Err(Error::CompleterDropped)
47            }
48        }
49    }
50}
51
52impl<T: Unpin + Send + 'static> Drop for FutureClicker<T> {
53    #[instrument(skip_all)]
54    fn drop(&mut self) {
55        use State::{Complete, Dropped, Incomplete, Waiting};
56        trace!("Drop");
57        let mut state = self.state.lock_arc();
58        trace!("Locked");
59
60        match mem::replace(&mut *state, Dropped) {
61            Incomplete | Dropped => {}
62            Waiting(waker) => waker.wake(),
63            old @ Complete(_) => *state = old,
64        }
65    }
66}