ach_option/
lib.rs

1#![no_std]
2use core::fmt;
3use core::mem::MaybeUninit;
4use core::ptr;
5use core::sync::atomic::Ordering::{Relaxed, SeqCst};
6use interrupt::CriticalSection;
7use util::*;
8
9pub struct AchOption<T> {
10    val: MaybeUninit<T>,
11    state: AtomicMemoryState,
12}
13impl<T> Default for AchOption<T> {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18impl<T> AchOption<T> {
19    pub const fn new() -> Self {
20        Self {
21            val: MaybeUninit::uninit(),
22            state: AtomicMemoryState::new(MemoryState::Uninitialized),
23        }
24    }
25    pub const fn new_with(init: T) -> Self {
26        Self {
27            val: MaybeUninit::new(init),
28            state: AtomicMemoryState::new(MemoryState::Initialized),
29        }
30    }
31    fn ptr(&self) -> *mut T {
32        self.val.as_ptr() as *mut T
33    }
34    pub fn into_inner(self) -> Option<T> {
35        self.take()
36    }
37    pub fn is_some(&self) -> bool {
38        let state = self.state.load(SeqCst);
39        state.is_initialized()
40    }
41    pub fn is_none(&self) -> bool {
42        let state = self.state.load(SeqCst);
43        state.is_uninitialized()
44    }
45
46    /// Takes ownership of the current value, leaving the cell uninitialized.
47    ///
48    /// Returns Err if the cell is in critical section.
49    pub fn try_take(&self) -> Result<Option<T>, Error<()>> {
50        let _cs = CriticalSection::new();
51        if let Err(state) = self.state.fetch_update(SeqCst, Relaxed, |x| {
52            if x.is_initialized() {
53                Some(MemoryState::Erasing)
54            } else {
55                None
56            }
57        }) {
58            if state.is_uninitialized() {
59                Ok(None)
60            } else {
61                Err(Error {
62                    state,
63                    input: (),
64                    retry: state.is_transient(),
65                })
66            }
67        } else {
68            let ret = unsafe { ptr::read(self.ptr()) };
69            self.state.store(MemoryState::Uninitialized, SeqCst);
70            Ok(Some(ret))
71        }
72    }
73    /// Takes ownership of the current value, leaving the cell uninitialized.
74    ///
75    /// Notice: `Spin`
76    pub fn take(&self) -> Option<T> {
77        unwrap(|_| self.try_take(), ())
78    }
79
80    /// Sets the value of the Option to the argument value.
81    ///
82    /// Returns Err if the value is initialized or in critical section.
83    pub fn try_set(&self, value: T) -> Result<(), Error<T>> {
84        let _cs = CriticalSection::new();
85        if let Err(state) = self.state.compare_exchange(
86            MemoryState::Uninitialized,
87            MemoryState::Initializing,
88            SeqCst,
89            Relaxed,
90        ) {
91            Err(Error {
92                state,
93                input: value,
94                retry: state.is_erasing(),
95            })
96        } else {
97            unsafe { ptr::write(self.ptr(), value) };
98            self.state.store(MemoryState::Initialized, SeqCst);
99            Ok(())
100        }
101    }
102    /// Sets the value of the Option to the argument value.
103    ///
104    /// Returns Err if the value is initialized.
105    /// Notice: `Spin`
106    pub fn set(&self, value: T) -> Result<(), Error<T>> {
107        retry(|val| self.try_set(val), value)
108    }
109
110    /// Replaces the contained value with value, and returns the old contained value.
111    ///
112    /// Returns Err if the value is in critical section.
113    pub fn try_replace(&self, value: T) -> Result<Option<T>, Error<T>> {
114        let _cs = CriticalSection::new();
115        match self.state.fetch_update(SeqCst, Relaxed, |x| {
116            if x.is_uninitialized() || x.is_initialized() {
117                Some(MemoryState::Initializing)
118            } else {
119                None
120            }
121        }) {
122            Ok(state) => {
123                let ret = if state.is_uninitialized() {
124                    None
125                } else {
126                    Some(unsafe { ptr::read(self.ptr()) })
127                };
128                unsafe { ptr::write(self.ptr(), value) };
129                self.state.store(MemoryState::Initialized, SeqCst);
130                Ok(ret)
131            }
132            Err(state) => Err(Error {
133                state,
134                input: value,
135                retry: state.is_transient(),
136            }),
137        }
138    }
139    /// Replaces the contained value with value, and returns the old contained value.
140    ///
141    /// Notice: `Spin`
142    pub fn replace(&self, value: T) -> Option<T> {
143        unwrap(|val| self.try_replace(val), value)
144    }
145}
146impl<T: fmt::Debug> fmt::Debug for AchOption<T> {
147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148        let v = if self.is_some() {
149            Some(unsafe { self.val.assume_init_ref() })
150        } else {
151            None
152        };
153        fmt::Debug::fmt(&v, f)
154    }
155}
156impl<T> Drop for AchOption<T> {
157    fn drop(&mut self) {
158        let _ = self.take();
159    }
160}