1 //! Synchronization primitives for lazy evaluation. 2 //! 3 //! Implementation adapted from the `SyncLazy` type of the standard library. See: 4 //! https://github.com/rust-lang/rust/blob/cae8bc1f2324e31c98cb32b8ed37032fc9cef405/library/std/src/lazy.rs 5 6 use core::{cell::Cell, fmt, ops::Deref}; 7 use crate::Once; 8 9 /// A value which is initialized on the first access. 10 /// 11 /// This type is a thread-safe `Lazy`, and can be used in statics. 12 /// 13 /// # Examples 14 /// 15 /// ``` 16 /// use std::collections::HashMap; 17 /// use spin::Lazy; 18 /// 19 /// static HASHMAP: Lazy<HashMap<i32, String>> = Lazy::new(|| { 20 /// println!("initializing"); 21 /// let mut m = HashMap::new(); 22 /// m.insert(13, "Spica".to_string()); 23 /// m.insert(74, "Hoyten".to_string()); 24 /// m 25 /// }); 26 /// 27 /// fn main() { 28 /// println!("ready"); 29 /// std::thread::spawn(|| { 30 /// println!("{:?}", HASHMAP.get(&13)); 31 /// }).join().unwrap(); 32 /// println!("{:?}", HASHMAP.get(&74)); 33 /// 34 /// // Prints: 35 /// // ready 36 /// // initializing 37 /// // Some("Spica") 38 /// // Some("Hoyten") 39 /// } 40 /// ``` 41 pub struct Lazy<T, F = fn() -> T> { 42 cell: Once<T>, 43 init: Cell<Option<F>>, 44 } 45 46 impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() 49 } 50 } 51 52 // We never create a `&F` from a `&Lazy<T, F>` so it is fine 53 // to not impl `Sync` for `F` 54 // we do create a `&mut Option<F>` in `force`, but this is 55 // properly synchronized, so it only happens once 56 // so it also does not contribute to this impl. 57 unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {} 58 // auto-derived `Send` impl is OK. 59 60 impl<T, F> Lazy<T, F> { 61 /// Creates a new lazy value with the given initializing 62 /// function. new(f: F) -> Lazy<T, F>63 pub const fn new(f: F) -> Lazy<T, F> { 64 Lazy { cell: Once::new(), init: Cell::new(Some(f)) } 65 } 66 } 67 68 impl<T, F: FnOnce() -> T> Lazy<T, F> { 69 /// Forces the evaluation of this lazy value and 70 /// returns a reference to result. This is equivalent 71 /// to the `Deref` impl, but is explicit. 72 /// 73 /// # Examples 74 /// 75 /// ``` 76 /// use spin::Lazy; 77 /// 78 /// let lazy = Lazy::new(|| 92); 79 /// 80 /// assert_eq!(Lazy::force(&lazy), &92); 81 /// assert_eq!(&*lazy, &92); 82 /// ``` force(this: &Lazy<T, F>) -> &T83 pub fn force(this: &Lazy<T, F>) -> &T { 84 this.cell.call_once(|| match this.init.take() { 85 Some(f) => f(), 86 None => panic!("Lazy instance has previously been poisoned"), 87 }) 88 } 89 } 90 91 impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { 92 type Target = T; deref(&self) -> &T93 fn deref(&self) -> &T { 94 Lazy::force(self) 95 } 96 } 97 98 impl<T: Default> Default for Lazy<T> { 99 /// Creates a new lazy value using `Default` as the initializing function. default() -> Lazy<T>100 fn default() -> Lazy<T> { 101 Lazy::new(T::default) 102 } 103 } 104