lock_free_static/
once_cell.rs1use core::{
2 cell::UnsafeCell,
3 mem::{ManuallyDrop, MaybeUninit, forget},
4 panic::{RefUnwindSafe, UnwindSafe},
5 ptr,
6 sync::atomic::{AtomicBool, Ordering},
7};
8
9struct Defer<F: FnOnce()> {
10 f: ManuallyDrop<F>,
11}
12impl<F: FnOnce()> Defer<F> {
13 pub fn new(f: F) -> Self {
14 Self {
15 f: ManuallyDrop::new(f),
16 }
17 }
18}
19impl<F: FnOnce()> Drop for Defer<F> {
20 fn drop(&mut self) {
21 (unsafe { ManuallyDrop::take(&mut self.f) })();
22 }
23}
24
25pub struct OnceCell<T> {
27 slot: UnsafeCell<MaybeUninit<T>>,
28 lock: AtomicBool,
29 init: AtomicBool,
30}
31
32unsafe impl<T: Send> Send for OnceCell<T> {}
33unsafe impl<T: Send + Sync> Sync for OnceCell<T> {}
34
35impl<T: UnwindSafe> UnwindSafe for OnceCell<T> {}
36impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceCell<T> {}
37
38impl<T> Default for OnceCell<T> {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl<T> OnceCell<T> {
45 pub const fn new() -> Self {
47 Self {
48 slot: UnsafeCell::new(MaybeUninit::uninit()),
49 lock: AtomicBool::new(false),
50 init: AtomicBool::new(false),
51 }
52 }
53
54 pub fn set(&self, value: T) -> Result<(), T> {
58 if self.lock.swap(true, Ordering::AcqRel) {
59 Err(value)
60 } else {
61 let slot = unsafe { &mut *self.slot.get() };
62 *slot = MaybeUninit::new(value);
63 self.init.store(true, Ordering::Release);
64 Ok(())
65 }
66 }
67
68 pub fn set_with<F: FnOnce() -> T>(&self, ctor: F) -> Result<(), F> {
76 if self.lock.swap(true, Ordering::AcqRel) {
77 Err(ctor)
78 } else {
79 let unlock = Defer::new(|| self.lock.store(false, Ordering::Release));
80 let value = ctor();
81 forget(unlock);
82
83 let slot = unsafe { &mut *self.slot.get() };
84 *slot = MaybeUninit::new(value);
85 self.init.store(true, Ordering::Release);
86 Ok(())
87 }
88 }
89
90 pub fn get_ptr(&self) -> Option<*mut T> {
94 if self.init.load(Ordering::Relaxed) {
95 Some(self.slot.get() as *mut T)
96 } else {
97 None
98 }
99 }
100
101 pub fn get(&self) -> Option<&T> {
105 self.get_ptr().map(|p| unsafe { &*p })
106 }
107
108 pub fn get_mut(&mut self) -> Option<&mut T> {
112 self.get_ptr().map(|p| unsafe { &mut *p })
113 }
114
115 pub fn take(&mut self) -> Option<T> {
119 if self.init.swap(false, Ordering::Relaxed) {
120 self.lock.store(false, Ordering::Relaxed);
121 Some(unsafe { ptr::read(self.slot.get()).assume_init() })
122 } else {
123 None
124 }
125 }
126
127 pub fn into_inner(mut self) -> Option<T> {
131 self.take()
132 }
133}
134
135impl<T> Drop for OnceCell<T> {
136 fn drop(&mut self) {
137 drop(self.take());
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::OnceCell;
144
145 #[test]
146 fn get() {
147 let mut cell = OnceCell::<i32>::new();
148 assert!(cell.get().is_none());
149
150 cell.set(123).unwrap();
151 assert_eq!(cell.set(321), Err(321));
152 assert_eq!(*cell.get().unwrap(), 123);
153
154 {
155 let value_mut = cell.get_mut().unwrap();
156 assert_eq!(*value_mut, 123);
157 *value_mut = 321;
158 assert_eq!(*value_mut, 321);
159 }
160 assert_eq!(*cell.get().unwrap(), 321);
161 }
162
163 #[test]
164 fn take() {
165 let mut cell = OnceCell::<i32>::new();
166 assert!(cell.get().is_none());
167
168 cell.set(123).unwrap();
169 assert_eq!(cell.set(321), Err(321));
170 assert_eq!(*cell.get().unwrap(), 123);
171
172 assert_eq!(cell.take().unwrap(), 123);
173 assert!(cell.get().is_none());
174 assert!(cell.take().is_none());
175
176 cell.set(321).unwrap();
177 assert_eq!(*cell.get().unwrap(), 321);
178 assert_eq!(cell.into_inner().unwrap(), 321);
179 }
180
181 #[test]
182 fn set_with() {
183 let cell = OnceCell::<i32>::new();
184
185 assert!(cell.set_with(|| 123).is_ok());
186 assert_eq!(*cell.get().unwrap(), 123);
187 assert!(cell.set_with(|| 321).is_err());
188 assert_eq!(*cell.get().unwrap(), 123);
189 }
190
191 #[test]
192 fn set_with_panic() {
193 extern crate std;
194 use std::panic::catch_unwind;
195
196 let cell = OnceCell::<i32>::new();
197
198 assert_eq!(
199 *catch_unwind(|| cell.set_with(|| panic!("abc")))
200 .err()
201 .unwrap()
202 .downcast::<&'static str>()
203 .unwrap(),
204 "abc"
205 );
206 assert!(cell.get().is_none());
207
208 cell.set(321).unwrap();
209 assert_eq!(*cell.get().unwrap(), 321);
210 }
211
212 static CELL: OnceCell<i32> = OnceCell::new();
213
214 #[test]
215 fn static_() {
216 assert!(CELL.get().is_none());
217
218 CELL.set(123).unwrap();
219 assert_eq!(CELL.set(321), Err(321));
220 assert_eq!(*CELL.get().unwrap(), 123);
221 }
222}