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