postage/sync/
oneshot_cell.rs

1use atomic::Ordering;
2
3use super::state_cell::StateCell;
4
5#[derive(Copy, Clone)]
6enum State {
7    None,
8    Writing,
9    Ready,
10    Taken,
11}
12
13pub enum TryRecvError {
14    Pending,
15    Closed,
16}
17
18pub struct OneshotCell<T> {
19    state: StateCell<State, T>,
20}
21
22impl<T> OneshotCell<T> {
23    pub fn new() -> Self {
24        Self {
25            state: StateCell::new(State::None),
26        }
27    }
28
29    pub fn send(&self, value: T) -> Result<(), T> {
30        unsafe {
31            self.state
32                .compare_store(
33                    State::None,
34                    State::Writing,
35                    value,
36                    State::Ready,
37                    Ordering::AcqRel,
38                    Ordering::Relaxed,
39                )
40                .map_err(|err| err.1)?;
41        }
42
43        Ok(())
44    }
45
46    pub fn try_recv(&self) -> Result<T, TryRecvError> {
47        unsafe {
48            match self.state.compare_take(
49                State::Ready,
50                State::Taken,
51                Ordering::AcqRel,
52                Ordering::Relaxed,
53            ) {
54                Ok(v) => Ok(v),
55                Err(e) => match e {
56                    State::None => Err(TryRecvError::Pending),
57                    State::Writing => Err(TryRecvError::Pending),
58                    State::Ready => unreachable!(),
59                    State::Taken => Err(TryRecvError::Closed),
60                },
61            }
62        }
63    }
64}