easylazy/
lib.rs

1//! EasyLazy - Lazy initialization made easy
2//! 
3//! Looking at the available options for lazy initialization, I found that the most
4//! required jumping through odd, unnecessary hoops.  EasyLazy aims to make lazy
5//! initialization of a variable lightweight and easy.
6//! 
7//! EasyLazy has only 3 requirements:
8//! - T must implement Clone
9//! - T must implement Default with a cheap operation
10//! - The Lazy variable must be mutable so that it can be initialized
11//! 
12//! Lazy is Send & Sync so long as T is Send & Sync.  Please make sure that your
13//! calculation is also thread safe before assuming YOUR Lazy variable is Send &
14//! Sync.
15
16#![no_std]
17
18extern crate alloc;
19use alloc::boxed::Box;
20
21/// A lazy variable of type T
22pub struct Lazy<T>
23where T: Clone + Default
24{
25    /// The value of the lazy variable
26    value: Option<T>,
27    /// The function to call to calculate the value of the lazy variable
28    calculation: Box<dyn Fn() -> T>,
29}
30
31unsafe impl<T> Send for Lazy<T>
32where T: Clone + Default + Send
33{
34    // Nothing to do here
35}
36
37unsafe impl<T> Sync for Lazy<T>
38where T: Clone + Default + Sync
39{
40    // Nothing to do here
41}
42
43impl<T> Lazy<T>
44where T: Clone + Default
45{
46    /// Create a new Lazy variable
47    /// 
48    /// # Arguments
49    /// * `calculation` - The function to call to calculate the value of the lazy variable
50    /// 
51    /// # Returns
52    /// A new Lazy variable
53    /// 
54    /// # Example
55    /// ```
56    /// use easylazy::Lazy;
57    /// let mut my_lazy_variable = Lazy::new(Box::new(|| 10));
58    /// // my_lazy_variable is uninitialized here
59    /// assert_eq!(my_lazy_variable.get(), 10);
60    /// ```
61    pub fn new(calculation: Box<dyn Fn() -> T>) -> Self 
62    {
63        Self 
64        {
65            value: None,
66            calculation,
67        }
68    }
69
70    /// Get the value of the lazy variable
71    /// 
72    /// # Returns
73    /// The value of the lazy variable
74    /// 
75    /// # Example
76    /// ```
77    /// use easylazy::Lazy;
78    /// let mut my_lazy_variable = Lazy::new(Box::new(|| 10));
79    /// // my_lazy_variable is uninitialized here
80    /// assert_eq!(my_lazy_variable.get(), 10);
81    /// ```
82    pub fn get(&mut self) -> T 
83    {
84        if self.value.is_some() 
85        {
86            return self.value.clone().unwrap()
87        }
88        self.value = Some((self.calculation)());
89        self.value.clone().unwrap()
90    }
91
92    /// Get a mutable reference to the value of the lazy variable
93    /// 
94    /// # Returns
95    /// A mutable reference to the value of the lazy variable
96    /// 
97    /// # Example
98    /// ```
99    /// use easylazy::Lazy;
100    /// let mut my_lazy_variable = Lazy::new(Box::new(|| 2 + 2));
101    /// // my_lazy_variable is uninitialized here
102    /// *my_lazy_variable.get_mut() = 42;
103    /// assert_eq!(my_lazy_variable.get(), 42);
104    /// ```
105    pub fn get_mut(&mut self) -> &mut T 
106    {
107        if self.value.is_none()
108        {
109            self.value = Some((self.calculation)());
110        }
111        if let Some(value) = self.value.as_mut()
112        {
113            value
114        }
115        else
116        {
117            panic!("Value inside Lazy is None after being set to Some(value)"); 
118        }
119    }
120}
121
122#[cfg(test)]
123mod tests 
124{
125    use super::*;
126
127    #[test]
128    fn get_test() 
129    {
130        let mut my_lazy_variable = Lazy::new(Box::new(|| 2 + 2));
131        assert_eq!(my_lazy_variable.get(), 4);
132    }
133
134    #[test]
135    fn get_mut_test()
136    {
137        let mut my_lazy_variable = Lazy::new(Box::new(|| 2 + 2));
138        let value = my_lazy_variable.get_mut();
139        *value = 10;
140        assert_eq!(my_lazy_variable.get(), 10);
141    }
142}