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}