1#![no_std]
2use core::fmt;
3use core::mem::MaybeUninit;
4use core::ptr;
5use core::sync::atomic::Ordering::SeqCst;
6use interrupt::CriticalSection;
7use util::*;
8
9pub struct Once<T> {
10 val: MaybeUninit<T>,
11 state: AtomicMemoryState,
12}
13impl<T> Once<T> {
14 pub const fn new() -> Self {
15 Once {
16 val: MaybeUninit::uninit(),
17 state: AtomicMemoryState::new(MemoryState::Uninitialized),
18 }
19 }
20 pub const fn new_with(init: T) -> Self {
21 Once {
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 is_initialized(&self) -> bool {
30 let state = self.state.load(SeqCst);
31 state.is_initialized()
32 }
33 pub fn take(&mut self) -> Option<T> {
34 if self.is_initialized() {
35 let ret = unsafe { ptr::read(self.ptr()) };
36 self.state.store(MemoryState::Uninitialized.into(), SeqCst);
37 Some(ret)
38 } else {
39 None
40 }
41 }
42 pub fn into_inner(self) -> Option<T> {
43 if self.is_initialized() {
44 let ret = unsafe { ptr::read(self.ptr()) };
45 Some(ret)
46 } else {
47 None
48 }
49 }
50
51 pub fn try_get(&self) -> Result<&T, Error<()>> {
55 let state = self.state.load(SeqCst);
56 if state.is_initialized() {
57 let ret = unsafe { self.val.assume_init_ref() };
58 Ok(ret)
59 } else {
60 Err(Error {
61 state,
62 input: (),
63 retry: state.is_initializing(),
64 })
65 }
66 }
67 pub fn get(&self) -> Result<&T, Error<()>> {
73 retry(|_| self.try_get(), ())
74 }
75 pub fn get_mut(&mut self) -> Option<&mut T> {
76 if self.is_initialized() {
77 let ret = unsafe { self.val.assume_init_mut() };
78 Some(ret)
79 } else {
80 None
81 }
82 }
83
84 pub fn try_set(&self, value: T) -> Result<(), Error<T>> {
88 let _cs = CriticalSection::new();
89 if let Err(state) = self.state.compare_exchange(
90 MemoryState::Uninitialized.into(),
91 MemoryState::Initializing.into(),
92 SeqCst,
93 SeqCst,
94 ) {
95 Err(Error {
96 state,
97 input: value,
98 retry: state.is_erasing(),
99 })
100 } else {
101 unsafe { ptr::write(self.ptr(), value) };
102 self.state.store(MemoryState::Initialized.into(), SeqCst);
103 Ok(())
104 }
105 }
106 pub fn set(&self, value: T) -> Result<(), Error<T>> {
112 retry(|val|self.try_set(val), value)
113 }
114
115 pub fn get_or_try_init(&self, value: T) -> Result<&T, Error<T>> {
119 let _cs = CriticalSection::new();
120 if let Err(_) = self.state.compare_exchange(
121 MemoryState::Uninitialized.into(),
122 MemoryState::Initializing.into(),
123 SeqCst,
124 SeqCst,
125 ) {
126 self.try_get().map_err(
127 |Error {
128 state,
129 input: _,
130 retry,
131 }| Error {
132 state,
133 input: value,
134 retry,
135 },
136 )
137 } else {
138 unsafe { ptr::write(self.ptr(), value) };
139 self.state.store(MemoryState::Initialized.into(), SeqCst);
140 Ok(unsafe { self.val.assume_init_ref() })
141 }
142 }
143 pub fn get_or_init(&self, mut value: T) -> &T {
147 loop {
148 match self.get_or_try_init(value) {
149 Ok(val) => return val,
150 Err(err) if err.retry => {
151 value = err.input;
152 spin_loop::spin();
153 continue;
154 }
155 Err(_) => unreachable!(),
156 }
157 }
158 }
159}
160impl<T: fmt::Debug> fmt::Debug for Once<T> {
161 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162 fmt::Debug::fmt(&self.get(), f)
163 }
164}
165impl<T> Drop for Once<T> {
166 fn drop(&mut self) {
167 self.take();
168 }
169}