lock_free_static/
once_cell.rs

1use 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
25/// Lock-free thread-safe cell which can be written to only once.
26pub 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    /// Creates a new empty cell.
40    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    /// Sets the contents of this cell to `value`.
49    ///
50    /// Returns `Ok(())` if the cell’s value was set by this call.
51    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    /// Sets the contents of this cell to value returned by `ctor` call.
63    ///
64    /// The `ctor` is called only if the cell’s value is going set by this call. Otherwice `ctor` returned in `Err(..)`.
65    ///
66    /// # Panics
67    ///
68    /// If `ctor` panics, the panic is propagated to the caller, and the cell remains uninitialized.
69    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    /// Gets the pointer to the underlying value.
85    ///
86    /// Returns `None` if the cell is empty.
87    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    /// Gets the reference to the underlying value.
96    ///
97    /// Returns `None` if the cell is empty, or being initialized.
98    pub fn get(&self) -> Option<&T> {
99        self.get_ptr().map(|p| unsafe { &*p })
100    }
101
102    /// Gets the mutable reference to the underlying value.
103    ///
104    /// Returns `None` if the cell is empty.
105    pub fn get_mut(&mut self) -> Option<&mut T> {
106        self.get_ptr().map(|p| unsafe { &mut *p })
107    }
108
109    /// Takes the value out of this cell, moving it back to an uninitialized state.
110    ///
111    /// Has no effect and returns `None` if the cell hasn’t been initialized.
112    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    /// Consumes the cell, returning the wrapped value.
122    ///
123    /// Returns `None` if the cell was empty.
124    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}