critical_once_cell/
lib.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Drop-in replacements for [`core::lazy::OnceCell`] and
6//! [`core::lazy::Lazy`], backed by [`critical_section`].
7//!
8//! ## Examples
9//! ### `CriticalOnceCell`
10//!
11//! ```
12//! use critical_once_cell::CriticalOnceCell;
13//!
14//! static CELL: CriticalOnceCell<String> = CriticalOnceCell::new();
15//!
16//! fn main() {
17//!     CELL.set("Hello, World!".to_owned()).unwrap();
18//!
19//!     assert_eq!(*CELL.get().unwrap(), "Hello, World!");
20//! }
21//! ```
22//!
23//! ### `CriticalLazy`
24//!
25//! ```
26//! use critical_once_cell::CriticalLazy;
27//!
28//! static LAZY: CriticalLazy<String> = CriticalLazy::new(|| "Hello, World!".to_owned());
29//!
30//! fn main() {
31//!     assert_eq!(*LAZY, "Hello, World!");
32//! }
33//! ```
34
35#![no_std]
36
37use core::{
38    cell::{Cell, UnsafeCell},
39    convert::Infallible,
40    ops::Deref,
41};
42
43/// A thread-safe cell which can be written to only once.
44///
45/// # Examples
46///
47/// ```
48/// use critical_once_cell::CriticalOnceCell;
49///
50/// let cell = CriticalOnceCell::new();
51/// assert!(cell.get().is_none());
52///
53/// let value: &String = cell.get_or_init(|| {
54///     "Hello, World!".to_string()
55/// });
56/// assert_eq!(value, "Hello, World!");
57/// assert!(cell.get().is_some());
58/// ```
59pub struct CriticalOnceCell<T> {
60    inner: UnsafeCell<Option<T>>,
61}
62
63impl<T> CriticalOnceCell<T> {
64    /// Creates a new empty cell.
65    pub const fn new() -> Self {
66        Self {
67            inner: UnsafeCell::new(None),
68        }
69    }
70
71    /// Gets the reference to the underlying value.
72    ///
73    /// Returns `None` if the cell is empty.
74    pub fn get(&self) -> Option<&T> {
75        critical_section::with(|_| {
76            let cell = unsafe { &mut *self.inner.get() };
77
78            cell.as_ref()
79        })
80    }
81
82    /// Gets the mutable reference to the underlying value.
83    ///
84    /// Returns `None` if the cell is empty.
85    pub fn get_mut(&mut self) -> Option<&mut T> {
86        critical_section::with(|_| {
87            let cell = unsafe { &mut *self.inner.get() };
88
89            cell.as_mut()
90        })
91    }
92
93    /// Sets the contents of the cell to `value`.
94    ///
95    /// # Errors
96    ///
97    /// This method returns `Ok(())` if the cell was empty and `Err(value)` if
98    /// it was full.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use critical_once_cell::CriticalOnceCell;
104    ///
105    /// let cell = CriticalOnceCell::new();
106    /// assert!(cell.get().is_none());
107    ///
108    /// assert_eq!(cell.set(92), Ok(()));
109    /// assert_eq!(cell.set(62), Err(62));
110    ///
111    /// assert!(cell.get().is_some());
112    /// ```
113    pub fn set(&self, value: T) -> Result<(), T> {
114        critical_section::with(|_| {
115            let cell = unsafe { &mut *self.inner.get() };
116
117            if cell.is_none() {
118                *cell = Some(value);
119                Ok(())
120            } else {
121                Err(value)
122            }
123        })
124    }
125
126    /// Gets the contents of the cell, initializing it with `f`
127    /// if the cell was empty.
128    ///
129    /// # Panics
130    ///
131    /// If `f` panics, the panic is propagated to the caller, and the cell
132    /// remains uninitialized.
133    ///
134    /// It is an error to reentrantly initialize the cell from `f`. Doing
135    /// so results in a panic.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use critical_once_cell::CriticalOnceCell;
141    ///
142    /// let cell = CriticalOnceCell::new();
143    /// let value = cell.get_or_init(|| 92);
144    /// assert_eq!(value, &92);
145    /// let value = cell.get_or_init(|| unreachable!());
146    /// assert_eq!(value, &92);
147    /// ```
148    pub fn get_or_init<F>(&self, f: F) -> &T
149    where
150        F: FnOnce() -> T,
151    {
152        unsafe {
153            self.get_or_try_init::<_, Infallible>(|| Ok(f()))
154                .unwrap_unchecked()
155        }
156    }
157
158    /// Gets the contents of the cell, initializing it with `f` if
159    /// the cell was empty. If the cell was empty and `f` failed, an
160    /// error is returned.
161    ///
162    /// # Panics
163    ///
164    /// If `f` panics, the panic is propagated to the caller, and the cell
165    /// remains uninitialized.
166    ///
167    /// It is an error to reentrantly initialize the cell from `f`. Doing
168    /// so results in a panic.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// use critical_once_cell::CriticalOnceCell;
174    ///
175    /// let cell = CriticalOnceCell::new();
176    /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
177    /// assert!(cell.get().is_none());
178    /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
179    ///     Ok(92)
180    /// });
181    /// assert_eq!(value, Ok(&92));
182    /// assert_eq!(cell.get(), Some(&92))
183    /// ```
184    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
185    where
186        F: FnOnce() -> Result<T, E>,
187    {
188        critical_section::with(|_| {
189            let cell = {
190                // Get shared reference first, to avoid retagging in case
191                // there are other references in use
192                let cell = unsafe { &*self.inner.get() };
193
194                if cell.is_none() {
195                    // In case the cell is empty, we can safely get a
196                    // unique reference
197                    let cell = unsafe { &mut *self.inner.get() };
198                    *cell = Some(f()?);
199
200                    // Return cell, converting to shared reference
201                    cell
202                } else {
203                    cell
204                }
205            };
206
207            Ok(unsafe { cell.as_ref().unwrap_unchecked() })
208        })
209    }
210
211    /// Consumes the cell, returning the wrapped value.
212    ///
213    /// Returns `None` if the cell was empty.
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// use critical_once_cell::CriticalOnceCell;
219    ///
220    /// let cell: CriticalOnceCell<String> = CriticalOnceCell::new();
221    /// assert_eq!(cell.into_inner(), None);
222    ///
223    /// let cell = CriticalOnceCell::new();
224    /// cell.set("hello".to_string()).unwrap();
225    /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
226    /// ```
227    pub fn into_inner(self) -> Option<T> {
228        self.inner.into_inner()
229    }
230
231    /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
232    ///
233    /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
234    ///
235    /// Safety is guaranteed by requiring a mutable reference.
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// use critical_once_cell::CriticalOnceCell;
241    ///
242    /// let mut cell: CriticalOnceCell<String> = CriticalOnceCell::new();
243    /// assert_eq!(cell.take(), None);
244    ///
245    /// let mut cell = CriticalOnceCell::new();
246    /// cell.set("hello".to_string()).unwrap();
247    /// assert_eq!(cell.take(), Some("hello".to_string()));
248    /// assert_eq!(cell.get(), None);
249    /// ```
250    pub fn take(&mut self) -> Option<T> {
251        critical_section::with(|_| {
252            let cell = unsafe { &mut *self.inner.get() };
253
254            cell.take()
255        })
256    }
257}
258
259unsafe impl<T> Sync for CriticalOnceCell<T> where T: Send + Sync {}
260
261/// A thread-safe value which is initialized on the first access.
262///
263/// # Examples
264///
265/// ```
266/// use critical_once_cell::CriticalLazy;
267///
268/// let lazy: CriticalLazy<i32> = CriticalLazy::new(|| {
269///     println!("initializing");
270///     92
271/// });
272/// println!("ready");
273/// println!("{}", *lazy);
274/// println!("{}", *lazy);
275///
276/// // Prints:
277/// //   ready
278/// //   initializing
279/// //   92
280/// //   92
281/// ```
282pub struct CriticalLazy<T, F = fn() -> T> {
283    cell: CriticalOnceCell<T>,
284    init: Cell<Option<F>>,
285}
286
287impl<T, F> CriticalLazy<T, F> {
288    pub const fn new(f: F) -> Self {
289        Self {
290            cell: CriticalOnceCell::new(),
291            init: Cell::new(Some(f)),
292        }
293    }
294}
295
296impl<T, F> CriticalLazy<T, F>
297where
298    F: FnOnce() -> T,
299{
300    pub fn force(this: &Self) -> &T {
301        this.cell.get_or_init(|| match this.init.take() {
302            Some(f) => f(),
303            None => panic!("`CriticalLazy` instance has previously been poisoned"),
304        })
305    }
306}
307
308impl<T, F> Deref for CriticalLazy<T, F>
309where
310    F: FnOnce() -> T,
311{
312    type Target = T;
313
314    fn deref(&self) -> &Self::Target {
315        Self::force(self)
316    }
317}
318
319unsafe impl<T, F> Sync for CriticalLazy<T, F>
320where
321    T: Send + Sync,
322    F: Send,
323{
324}
325
326#[cfg(test)]
327#[macro_use]
328extern crate std;
329
330#[cfg(test)]
331mod tests {
332    use core::sync::atomic::{AtomicUsize, Ordering};
333    use std::thread;
334
335    use std::vec::Vec;
336
337    use std::boxed::Box;
338
339    use std::sync::Arc;
340
341    use super::*;
342
343    #[test]
344    fn cell() {
345        let mut cell = CriticalOnceCell::new();
346
347        assert!(cell.get().is_none());
348        assert!(cell.take().is_none());
349
350        assert!(cell.set(42).is_ok());
351        assert_eq!(cell.set(42), Err(42));
352
353        assert_eq!(*cell.get().unwrap(), 42);
354        assert_eq!(cell.take(), Some(42));
355        assert!(cell.take().is_none());
356
357        assert!(cell.set(43).is_ok());
358        assert_eq!(cell.set(43), Err(43));
359
360        assert_eq!(*cell.get().unwrap(), 43);
361    }
362
363    #[test]
364    fn cell_mut() {
365        let mut cell = CriticalOnceCell::new();
366        assert!(cell.set(42).is_ok());
367
368        let inner = cell.get_mut().unwrap();
369
370        *inner = 44;
371
372        assert_eq!(*cell.get().unwrap(), 44);
373    }
374
375    #[test]
376    fn get_or_init() {
377        let cell = CriticalOnceCell::new();
378
379        assert_eq!(*cell.get_or_init(|| 42), 42);
380        assert_eq!(*cell.get_or_init(|| 43), 42);
381    }
382
383    #[test]
384    fn get_or_try_init() {
385        let cell = CriticalOnceCell::new();
386
387        assert!(cell.get_or_try_init(|| Err(())).is_err());
388        assert_eq!(*cell.get_or_try_init::<_, ()>(|| Ok(42)).unwrap(), 42);
389        assert_eq!(*cell.get_or_try_init::<_, ()>(|| Ok(43)).unwrap(), 42);
390        assert_eq!(*cell.get_or_try_init(|| Err(())).unwrap(), 42);
391    }
392
393    #[test]
394    fn threads() {
395        let cell = Arc::new(CriticalOnceCell::new());
396
397        let handles: Vec<_> = (0..10)
398            .map(|i| {
399                let cell = cell.clone();
400
401                thread::spawn(move || {
402                    let value = Box::new(i);
403                    let res = cell.set(value);
404
405                    if res.is_ok() {
406                        Some(i)
407                    } else {
408                        None
409                    }
410                })
411            })
412            .collect();
413
414        let values: Vec<_> = handles
415            .into_iter()
416            .map(|handle| handle.join().unwrap())
417            .collect();
418
419        for value in values {
420            if let Some(value) = value {
421                assert_eq!(value, **cell.get().unwrap());
422            }
423        }
424    }
425
426    #[test]
427    fn lazy() {
428        let init = Cell::new(0);
429        let counter = CriticalLazy::new(|| {
430            init.set(init.get() + 1);
431            AtomicUsize::new(0)
432        });
433
434        for _ in 0..10 {
435            counter.fetch_add(1, Ordering::Relaxed);
436        }
437
438        assert_eq!(init.get(), 1);
439        assert_eq!(counter.load(Ordering::Relaxed), 10);
440    }
441
442    #[test]
443    fn lazy_threads() {
444        const N: usize = 100;
445        let counter = Arc::new(CriticalLazy::new(|| AtomicUsize::new(0)));
446
447        let handles: Vec<_> = (0..N)
448            .map(|_| {
449                let counter = counter.clone();
450                thread::spawn(move || {
451                    counter.fetch_add(1, Ordering::Relaxed);
452                })
453            })
454            .collect();
455
456        for handle in handles {
457            handle.join().unwrap();
458        }
459
460        assert_eq!(counter.load(Ordering::Relaxed), N);
461    }
462}