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}