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 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 pub fn take(&self) -> Option<T> {
72 unwrap(|_| self.try_take(), ())
73 }
74
75 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 pub fn set(&self, value: T) -> Result<(), Error<T>> {
102 retry(|val| self.try_set(val), value)
103 }
104
105 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 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}