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 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}