• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[cfg(feature = "std")]
2 pub(crate) use once_cell::sync::Lazy;
3 
4 #[cfg(not(feature = "std"))]
5 pub(crate) use self::spin::Lazy;
6 
7 #[cfg(not(feature = "std"))]
8 mod spin {
9     //! This is the `once_cell::sync::Lazy` type, but modified to use our
10     //! `spin::Once` type rather than `OnceCell`. This is used to replace
11     //! `once_cell::sync::Lazy` on `no-std` builds.
12     use crate::spin::Once;
13     use core::{cell::Cell, fmt, ops::Deref};
14 
15     /// Re-implementation of `once_cell::sync::Lazy` on top of `spin::Once`
16     /// rather than `OnceCell`.
17     ///
18     /// This is used when the standard library is disabled.
19     pub(crate) struct Lazy<T, F = fn() -> T> {
20         cell: Once<T>,
21         init: Cell<Option<F>>,
22     }
23 
24     impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result25         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26             f.debug_struct("Lazy")
27                 .field("cell", &self.cell)
28                 .field("init", &"..")
29                 .finish()
30         }
31     }
32 
33     // We never create a `&F` from a `&Lazy<T, F>` so it is fine to not impl
34     // `Sync` for `F`. We do create a `&mut Option<F>` in `force`, but this is
35     // properly synchronized, so it only happens once so it also does not
36     // contribute to this impl.
37     unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {}
38     // auto-derived `Send` impl is OK.
39 
40     impl<T, F> Lazy<T, F> {
41         /// Creates a new lazy value with the given initializing function.
new(init: F) -> Lazy<T, F>42         pub(crate) const fn new(init: F) -> Lazy<T, F> {
43             Lazy {
44                 cell: Once::new(),
45                 init: Cell::new(Some(init)),
46             }
47         }
48     }
49 
50     impl<T, F: FnOnce() -> T> Lazy<T, F> {
51         /// Forces the evaluation of this lazy value and returns a reference to
52         /// the result.
53         ///
54         /// This is equivalent to the `Deref` impl, but is explicit.
force(this: &Lazy<T, F>) -> &T55         pub(crate) fn force(this: &Lazy<T, F>) -> &T {
56             this.cell.call_once(|| match this.init.take() {
57                 Some(f) => f(),
58                 None => panic!("Lazy instance has previously been poisoned"),
59             })
60         }
61     }
62 
63     impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
64         type Target = T;
deref(&self) -> &T65         fn deref(&self) -> &T {
66             Lazy::force(self)
67         }
68     }
69 
70     impl<T: Default> Default for Lazy<T> {
71         /// Creates a new lazy value using `Default` as the initializing function.
default() -> Lazy<T>72         fn default() -> Lazy<T> {
73             Lazy::new(T::default)
74         }
75     }
76 }
77