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 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 pub fn take(&self) -> Option<T> {
77 unwrap(|_| self.try_take(), ())
78 }
79
80 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 pub fn set(&self, value: T) -> Result<(), Error<T>> {
107 retry(|val| self.try_set(val), value)
108 }
109
110 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 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}