ach_cell/
lib.rs

1#![no_std]
2use core::fmt;
3use core::mem::MaybeUninit;
4use core::ops::Deref;
5use core::ptr;
6use core::sync::atomic::Ordering::{Relaxed, SeqCst};
7use interrupt::CriticalSection;
8use util::*;
9
10pub struct Ref<'a, T>(&'a Cell<T>);
11impl<'a, T> Ref<'a, T> {
12    pub fn ref_num(&self) -> Result<usize, MemoryState> {
13        self.0.ref_num()
14    }
15    /// Will remove the val of cell, after drop all Ref.
16    pub fn remove(&self) {
17        let _ = self.0.state.fetch_update(SeqCst, Relaxed, |mut x| {
18            x.set_state(MemoryState::Erasing);
19            Some(x)
20        });
21    }
22    pub fn will_remove(&self) -> bool {
23        self.0.state.load(SeqCst).state().is_erasing()
24    }
25}
26impl<'a, T> Deref for Ref<'a, T> {
27    type Target = T;
28    fn deref(&self) -> &Self::Target {
29        unsafe { self.0.val.assume_init_ref() }
30    }
31}
32impl<'a, T: fmt::Debug> fmt::Debug for Ref<'a, T> {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        let v: &T = self;
35        fmt::Debug::fmt(&v, f)
36    }
37}
38impl<'a, T> Drop for Ref<'a, T> {
39    fn drop(&mut self) {
40        let _cs = CriticalSection::new();
41        let old = match self.0.state.fetch_update(SeqCst, Relaxed, |mut x| {
42            if x.ref_sub().is_ok() {
43                Some(x)
44            } else {
45                None
46            }
47        }) {
48            Ok(v) => v,
49            Err(v) => v,
50        };
51        let will_drop = self.will_remove();
52        if old.ref_num() == Ok(1) && will_drop {
53            unsafe { ptr::drop_in_place(self.0.val.as_ptr() as *mut T) };
54            self.0
55                .state
56                .store(MemoryState::Uninitialized.into(), SeqCst);
57        }
58    }
59}
60
61pub struct Cell<T> {
62    val: MaybeUninit<T>,
63    state: AtomicMemoryRefer,
64}
65impl<T> Default for Cell<T> {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70impl<T> Cell<T> {
71    pub const fn new() -> Self {
72        Cell {
73            val: MaybeUninit::uninit(),
74            state: AtomicMemoryRefer::new(MemoryRefer::new()),
75        }
76    }
77    pub const fn new_with(init: T) -> Self {
78        Cell {
79            val: MaybeUninit::new(init),
80            state: AtomicMemoryRefer::new(MemoryRefer::new()),
81        }
82    }
83    fn ptr(&self) -> *mut T {
84        self.val.as_ptr() as *mut T
85    }
86    pub fn is_initialized(&self) -> bool {
87        let state = self.state.load(SeqCst);
88        state.state().is_initialized()
89    }
90    pub fn ref_num(&self) -> Result<usize, MemoryState> {
91        self.state.load(SeqCst).ref_num()
92    }
93
94    /// Takes ownership of the current value, leaving the cell uninitialized.
95    ///
96    /// Returns Err if the cell is refered or in critical section.
97    pub fn try_take(&self) -> Result<Option<T>, Error<()>> {
98        let _cs = CriticalSection::new();
99        let refer = match self.state.fetch_update(SeqCst, Relaxed, |mut x| {
100            let state = x.state();
101            if state.is_initialized() || state.is_regaining() {
102                if x.ref_num() == Ok(0) {
103                    x.set_state(MemoryState::Erasing);
104                } else {
105                    x.set_state(MemoryState::Regaining);
106                }
107                Some(x)
108            } else {
109                None
110            }
111        }) {
112            Ok(v) => v,
113            Err(v) => v,
114        };
115
116        match refer.state() {
117            MemoryState::Uninitialized => Ok(None),
118            MemoryState::Initialized | MemoryState::Regaining => {
119                if refer.ref_num() == Ok(0) {
120                    let ret = unsafe { ptr::read(self.ptr()) };
121                    self.state.store(MemoryState::Uninitialized.into(), SeqCst);
122                    Ok(Some(ret))
123                } else {
124                    Err(Error {
125                        state: MemoryState::Regaining,
126                        input: (),
127                        retry: true,
128                    })
129                }
130            }
131            state => Err(Error {
132                state,
133                input: (),
134                retry: state.is_transient(),
135            }),
136        }
137    }
138    /// Takes ownership of the current value, leaving the cell uninitialized.
139    ///
140    /// Returns Err is unreachable.
141    ///
142    /// Notice: `Spin`
143    pub fn take(&self) -> Result<Option<T>, Error<()>> {
144        retry(|_| self.try_take(), ())
145    }
146
147    /// # Safety
148    /// Calling this when the content is not yet fully initialized causes undefined behavior: it is up to the caller to guarantee that the MaybeUninit<T> really is in an initialized state.
149    pub unsafe fn peek(&self) -> &T {
150        self.val.assume_init_ref()
151    }
152    /// Tries to get a reference to the value of the Cell.
153    ///
154    /// Returns Err if the cell is uninitialized, in operation or in critical section.
155    pub fn try_get(&self) -> Result<Ref<'_, T>, Error<()>> {
156        if let Err(state) = self.state.fetch_update(SeqCst, Relaxed, |mut x| {
157            if x.ref_add().is_ok() {
158                Some(x)
159            } else {
160                None
161            }
162        }) {
163            let state = state.state();
164            Err(Error {
165                state,
166                input: (),
167                retry: state.is_initializing(),
168            })
169        } else {
170            Ok(Ref(self))
171        }
172    }
173    /// Tries to get a reference to the value of the Cell.
174    ///
175    /// Returns Err if the cell is uninitialized.
176    ///
177    /// Notice: `Spin`
178    pub fn get(&self) -> Result<Ref<'_, T>, Error<()>> {
179        retry(|_| self.try_get(), ())
180    }
181
182    /// Sets the value of the Cell to the argument value.
183    ///
184    /// Returns Err if the value is refered, initialized or in critical section.
185    pub fn try_set(&self, value: T) -> Result<(), Error<T>> {
186        let _cs = CriticalSection::new();
187        if let Err(state) = self.state.compare_exchange(
188            MemoryState::Uninitialized.into(),
189            MemoryState::Initializing.into(),
190            SeqCst,
191            SeqCst,
192        ) {
193            let state = state.state();
194            Err(Error {
195                state,
196                input: value,
197                retry: state.is_erasing(),
198            })
199        } else {
200            unsafe { ptr::write(self.ptr(), value) };
201            self.state.store(MemoryState::Initialized.into(), SeqCst);
202            Ok(())
203        }
204    }
205    /// Sets the value of the Cell to the argument value.
206    ///
207    /// Returns Err if the value is refered, initialized.
208    ///
209    /// Notice: `Spin`
210    pub fn set(&self, value: T) -> Result<(), Error<T>> {
211        retry(|v| self.try_set(v), value)
212    }
213
214    /// Replaces the contained value with value, and returns the old contained value.
215    ///
216    /// Returns Err if the value is refered or in critical section.
217    pub fn try_replace(&self, value: T) -> Result<Option<T>, Error<T>> {
218        let _cs = CriticalSection::new();
219        let refer = match self.state.fetch_update(SeqCst, Relaxed, |mut x| {
220            let state = x.state();
221            if state.is_initialized() || state.is_regaining() {
222                if x.ref_num() == Ok(0) {
223                    x.set_state(MemoryState::Initializing);
224                } else {
225                    x.set_state(MemoryState::Regaining);
226                }
227                Some(x)
228            } else if state.is_uninitialized() {
229                x.set_state(MemoryState::Initializing);
230                Some(x)
231            } else {
232                None
233            }
234        }) {
235            Ok(v) => v,
236            Err(v) => v,
237        };
238
239        match refer.state() {
240            MemoryState::Uninitialized => {
241                unsafe { ptr::write(self.ptr(), value) };
242                self.state.store(MemoryState::Initialized.into(), SeqCst);
243                Ok(None)
244            }
245            MemoryState::Initialized | MemoryState::Regaining => {
246                if refer.ref_num() == Ok(0) {
247                    let ret = unsafe { ptr::read(self.ptr()) };
248                    unsafe { ptr::write(self.ptr(), value) };
249                    self.state.store(MemoryState::Initialized.into(), SeqCst);
250                    Ok(Some(ret))
251                } else {
252                    Err(Error {
253                        state: MemoryState::Regaining,
254                        input: value,
255                        retry: true,
256                    })
257                }
258            }
259            state => Err(Error {
260                state,
261                input: value,
262                retry: state.is_transient(),
263            }),
264        }
265    }
266    /// Replaces the contained value with value, and returns the old contained value.
267    ///
268    /// Returns Err is unreachable.
269    ///
270    /// Notice: `Spin`
271    pub fn replace(&self, value: T) -> Result<Option<T>, Error<T>> {
272        retry(|v| self.try_replace(v), value)
273    }
274
275    /// Tries to get a reference to the value of the Cell.
276    ///
277    /// Returns Err if the cell is in critical section.
278    pub fn get_or_try_init(&self, value: T) -> Result<Ref<'_, T>, Error<T>> {
279        let ret = self.try_set(value);
280        if let Ok(v) = self.try_get() {
281            Ok(v)
282        } else {
283            Err(ret.unwrap_err())
284        }
285    }
286    /// Tries to get a reference to the value of the Cell.
287    ///
288    /// Notice: `Spin`
289    pub fn get_or_init(&self, value: T) -> Ref<'_, T> {
290        retry(|v| self.get_or_try_init(v), value).unwrap()
291    }
292}
293impl<T: fmt::Debug> fmt::Debug for Cell<T> {
294    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
295        let v = self.try_get().ok();
296        fmt::Debug::fmt(&v, f)
297    }
298}
299impl<T> Drop for Cell<T> {
300    fn drop(&mut self) {
301        let _ = self.take();
302    }
303}