1 //! `LazyStatic` like initialization. 2 3 /// The initialization state 4 enum State<F, T> { 5 /// The data is uninitialized, initialization is pending. 6 /// 7 /// The inner closure contains the initialization function. 8 Uninitialized(F), 9 /// The data is initialized, and ready for use. 10 Initialized(T), 11 } 12 13 /// A lazily initialized container. 14 /// 15 /// This container starts out simply containing an initializer (i.e., a function to construct the 16 /// value in question). When the value is requested, the initializer runs. 17 pub struct LazyInit<F, T> { 18 /// The internal state. 19 state: State<F, T>, 20 } 21 22 impl<F: FnMut() -> T, T> LazyInit<F, T> { 23 /// Create a new to-be-initialized container. 24 /// 25 /// The closure will be executed when initialization is required, and is guaranteed to be 26 /// executed at most once. 27 #[inline] 28 pub const fn new(init: F) -> LazyInit<F, T> { 29 LazyInit { 30 state: State::Uninitialized(init), 31 } 32 } 33 34 /// Get a mutable reference to the inner value. 35 /// 36 /// If it is uninitialize, it will be initialized and then returned. 37 #[inline] 38 pub fn get(&mut self) -> &mut T { 39 let inner; 40 41 match self.state { 42 State::Initialized(ref mut x) => return x, 43 State::Uninitialized(ref mut f) => inner = f(), 44 } 45 46 self.state = State::Initialized(inner); 47 48 if let State::Initialized(ref mut x) = self.state { 49 x 50 } else { 51 // TODO: Find a better way to deal with this case. 52 unreachable!(); 53 } 54 } 55 56 /// Get the inner of the container. 57 /// 58 /// This won't mutate the container itself, since it consumes it. The initializer will (if 59 /// necessary) be called and the result returned. If already initialized, the inner value will 60 /// be moved out and returned. 61 pub fn into_inner(self) -> T { 62 match self.state { 63 State::Initialized(x) => x, 64 State::Uninitialized(mut f) => f(), 65 } 66 } 67 } 68 69 #[cfg(test)] 70 mod test { 71 use super::*; 72 73 use core::cell::Cell; 74 75 #[test] 76 fn test_init() { 77 let mut lazy = LazyInit::new(|| 300); 78 79 assert_eq!(*lazy.get(), 300); 80 *lazy.get() = 400; 81 assert_eq!(*lazy.get(), 400); 82 } 83 84 #[test] 85 fn test_laziness() { 86 let is_called = Cell::new(false); 87 let mut lazy = LazyInit::new(|| is_called.set(true)); 88 assert!(!is_called.get()); 89 lazy.get(); 90 assert!(is_called.get()); 91 } 92 } 93