lock_free_static/
once_cell.rs1use core::{
2 cell::UnsafeCell,
3 mem::{forget, ManuallyDrop, MaybeUninit},
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> OnceCell<T> {
39 pub const fn new() -> Self {
41 Self {
42 slot: UnsafeCell::new(MaybeUninit::uninit()),
43 lock: AtomicBool::new(false),
44 init: AtomicBool::new(false),
45 }
46 }
47
48 pub fn set(&self, value: T) -> Result<(), T> {
52 if self.lock.swap(true, Ordering::AcqRel) {
53 Err(value)
54 } else {
55 let slot = unsafe { &mut *self.slot.get() };
56 *slot = MaybeUninit::new(value);
57 self.init.store(true, Ordering::Release);
58 Ok(())
59 }
60 }
61
62 pub fn set_with<F: FnOnce() -> T>(&self, ctor: F) -> Result<(), F> {
70 if self.lock.swap(true, Ordering::AcqRel) {
71 Err(ctor)
72 } else {
73 let unlock = Defer::new(|| self.lock.store(false, Ordering::Release));
74 let value = ctor();
75 forget(unlock);
76
77 let slot = unsafe { &mut *self.slot.get() };
78 *slot = MaybeUninit::new(value);
79 self.init.store(true, Ordering::Release);
80 Ok(())
81 }
82 }
83
84 pub fn get_ptr(&self) -> Option<*mut T> {
88 if self.init.load(Ordering::Relaxed) {
89 Some(self.slot.get() as *mut T)
90 } else {
91 None
92 }
93 }
94
95 pub fn get(&self) -> Option<&T> {
99 self.get_ptr().map(|p| unsafe { &*p })
100 }
101
102 pub fn get_mut(&mut self) -> Option<&mut T> {
106 self.get_ptr().map(|p| unsafe { &mut *p })
107 }
108
109 pub fn take(&mut self) -> Option<T> {
113 if self.init.swap(false, Ordering::Relaxed) {
114 self.lock.store(false, Ordering::Relaxed);
115 Some(unsafe { ptr::read(self.slot.get()).assume_init() })
116 } else {
117 None
118 }
119 }
120
121 pub fn into_inner(mut self) -> Option<T> {
125 self.take()
126 }
127}
128
129impl<T> Drop for OnceCell<T> {
130 fn drop(&mut self) {
131 drop(self.take());
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::OnceCell;
138
139 #[test]
140 fn get() {
141 let mut cell = OnceCell::<i32>::new();
142 assert!(cell.get().is_none());
143
144 cell.set(123).unwrap();
145 assert_eq!(cell.set(321), Err(321));
146 assert_eq!(*cell.get().unwrap(), 123);
147
148 {
149 let value_mut = cell.get_mut().unwrap();
150 assert_eq!(*value_mut, 123);
151 *value_mut = 321;
152 assert_eq!(*value_mut, 321);
153 }
154 assert_eq!(*cell.get().unwrap(), 321);
155 }
156
157 #[test]
158 fn take() {
159 let mut cell = OnceCell::<i32>::new();
160 assert!(cell.get().is_none());
161
162 cell.set(123).unwrap();
163 assert_eq!(cell.set(321), Err(321));
164 assert_eq!(*cell.get().unwrap(), 123);
165
166 assert_eq!(cell.take().unwrap(), 123);
167 assert!(cell.get().is_none());
168 assert!(cell.take().is_none());
169
170 cell.set(321).unwrap();
171 assert_eq!(*cell.get().unwrap(), 321);
172 assert_eq!(cell.into_inner().unwrap(), 321);
173 }
174
175 #[test]
176 fn set_with() {
177 let cell = OnceCell::<i32>::new();
178
179 assert!(cell.set_with(|| 123).is_ok());
180 assert_eq!(*cell.get().unwrap(), 123);
181 assert!(cell.set_with(|| 321).is_err());
182 assert_eq!(*cell.get().unwrap(), 123);
183 }
184
185 #[test]
186 fn set_with_panic() {
187 extern crate std;
188 use std::panic::catch_unwind;
189
190 let cell = OnceCell::<i32>::new();
191
192 assert_eq!(
193 *catch_unwind(|| cell.set_with(|| panic!("abc")))
194 .err()
195 .unwrap()
196 .downcast::<&'static str>()
197 .unwrap(),
198 "abc"
199 );
200 assert!(cell.get().is_none());
201
202 cell.set(321).unwrap();
203 assert_eq!(*cell.get().unwrap(), 321);
204 }
205
206 static CELL: OnceCell<i32> = OnceCell::new();
207
208 #[test]
209 fn static_() {
210 assert!(CELL.get().is_none());
211
212 CELL.set(123).unwrap();
213 assert_eq!(CELL.set(321), Err(321));
214 assert_eq!(*CELL.get().unwrap(), 123);
215 }
216}