salsa/
blocking_future.rs

1use parking_lot::{Condvar, Mutex};
2use std::mem;
3use std::sync::Arc;
4
5pub(crate) struct BlockingFuture<T> {
6    slot: Arc<Slot<T>>,
7}
8
9pub(crate) struct Promise<T> {
10    fulfilled: bool,
11    slot: Arc<Slot<T>>,
12}
13
14impl<T> BlockingFuture<T> {
15    pub(crate) fn new() -> (BlockingFuture<T>, Promise<T>) {
16        let future = BlockingFuture {
17            slot: Default::default(),
18        };
19        let promise = Promise {
20            fulfilled: false,
21            slot: Arc::clone(&future.slot),
22        };
23        (future, promise)
24    }
25
26    pub(crate) fn wait(self) -> Option<T> {
27        let mut guard = self.slot.lock.lock();
28        if guard.is_empty() {
29            // parking_lot guarantees absence of spurious wake ups
30            self.slot.cvar.wait(&mut guard);
31        }
32        match mem::replace(&mut *guard, State::Dead) {
33            State::Empty => unreachable!(),
34            State::Full(it) => Some(it),
35            State::Dead => None,
36        }
37    }
38}
39
40impl<T> Promise<T> {
41    pub(crate) fn fulfil(mut self, value: T) {
42        self.fulfilled = true;
43        self.transition(State::Full(value));
44    }
45    fn transition(&mut self, new_state: State<T>) {
46        let mut guard = self.slot.lock.lock();
47        *guard = new_state;
48        self.slot.cvar.notify_one();
49    }
50}
51
52impl<T> Drop for Promise<T> {
53    fn drop(&mut self) {
54        if !self.fulfilled {
55            self.transition(State::Dead);
56        }
57    }
58}
59
60struct Slot<T> {
61    lock: Mutex<State<T>>,
62    cvar: Condvar,
63}
64
65impl<T> Default for Slot<T> {
66    fn default() -> Slot<T> {
67        Slot {
68            lock: Mutex::new(State::Empty),
69            cvar: Condvar::new(),
70        }
71    }
72}
73
74enum State<T> {
75    Empty,
76    Full(T),
77    Dead,
78}
79
80impl<T> State<T> {
81    fn is_empty(&self) -> bool {
82        matches!(self, State::Empty)
83    }
84}