1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
use std::cell::{ Cell, RefCell, Ref, RefMut }; use std::ops::{ Deref, DerefMut }; use std::borrow::{ Borrow, BorrowMut }; // // Constants // const EXPECT_VALUE_CELL_INITIALIZED: &str = "option in value_cell must be initialized at this point"; const EXPECT_EVALUATOR_STILL_PRESENT: &str = "evaluator must still be present at this point"; const EXPECT_VALUE_CELL_PTR_NOT_NULL: &str = "value_cell as ptr must not be null"; // // Interface // // // struct Lazy<T, Eval>: Deref<Target = T> + DerefMut + AsRef<T> + Borrow<T> + BorrowMut<T> // /// Contains a value of some type `T`, lazily evaluated using a parameterless /// function or a closure (`FnOnce() -> T`) passed to [`Lazy::new()`](struct.Lazy.html#method.new). /// /// This type provides pointer-like interface to the evaluation result, /// implementing [`Deref`](https://doc.rust-lang.org/nightly/core/ops/deref/trait.Deref.html), /// [`AsRef`](https://doc.rust-lang.org/nightly/core/convert/trait.AsRef.html), /// [`Borrow`](https://doc.rust-lang.org/nightly/core/borrow/trait.Borrow.html) /// and their `Mut` counterparts. /// /// The result will be evaluated the first time it is accessed via any of `Lazy`'s methods. /// /// # Accessing evaluated value /// /// A `Lazy` value can be acessed in any of the following ways: /// ``` /// use sloth::Lazy; /// /// let mut lazy_value = Lazy::new(|| 2019); /// /// let value: i32 = *lazy_value; /// let value_ref: &i32 = lazy_value.as_ref(); /// let value_mut: &mut i32 = lazy_value.as_mut(); /// /// let value_copy: i32 = lazy_value.value(); // only for types implementing Copy /// /// let value: i32 = lazy_value.unwrap(); // consumes lazy_value /// ``` /// /// Due to [`Deref` coercion](https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-deref-coercion) /// `T`'s methods may be called directly on [`Lazy<T, Eval>`](struct.Lazy.html), while references to `Lazy` /// are coerced to references to `T`: /// ``` /// use sloth::Lazy; /// /// fn print_string_len(string: &String) { /// println!("{} has length {}", string, string.len()); /// } /// /// let mut lazy_string = Lazy::new(|| String::from("lorem ")); /// /// lazy_string.push_str("ipsum"); // can call T's methods /// /// print_string_len(&lazy_string); // can pass as &T function param /// /// ``` /// /// # Laziness /// /// The evaluator function will not be called more than once, /// regardless of how many times the value is accessed: /// ``` /// use sloth::Lazy; /// /// let mut evaluator_called_times = 0; /// /// let lazy_value = Lazy::new(|| { /// evaluator_called_times += 1; /// 25 /// }); /// /// assert_eq!(*lazy_value, 25); /// /// let another_value = *lazy_value + *lazy_value; /// /// assert_eq!(evaluator_called_times, 1); /// ``` /// /// If a `Lazy` value is never dereferenced and none of its methods are called, /// its evaluator function will not be invoked at all. pub struct Lazy<T, Eval> where Eval: FnOnce() -> T { evaluator_cell: Cell<Option<Eval>>, value_cell: RefCell<Option<T>> } // // Trait impls // impl<T, Eval> Deref for Lazy<T, Eval> where Eval: FnOnce() -> T { type Target = T; /// Immutable dereference, allowing access to the contained value. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. fn deref(&self) -> &T { self.as_ref_impl() } } impl<T, Eval> DerefMut for Lazy<T, Eval> where Eval: FnOnce() -> T { /// Mutable dereference, allowing access to the contained value. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. fn deref_mut(&mut self) -> &mut T { self.as_mut_impl() } } impl<T, Eval> AsRef<T> for Lazy<T, Eval> where Eval: FnOnce() -> T { /// Immutably borrows the evaluation result. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. fn as_ref(&self) -> &T { self.as_ref_impl() } } impl<T, Eval> AsMut<T> for Lazy<T, Eval> where Eval: FnOnce() -> T { /// Mutably borrows the evaluation result. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. fn as_mut(&mut self) -> &mut T { self.as_mut_impl() } } impl<T, Eval> Borrow<T> for Lazy<T, Eval> where Eval: FnOnce() -> T { /// Immutably borrows the evaluation result. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. fn borrow(&self) -> &T { self.as_ref_impl() } } impl<T, Eval> BorrowMut<T> for Lazy<T, Eval> where Eval: FnOnce() -> T { /// Mutably borrows the evaluation result. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. fn borrow_mut(&mut self) -> &mut T { self.as_mut_impl() } } // // Methods // impl<T, Eval> Lazy<T, Eval> where Eval: FnOnce() -> T { // // Interface // /// Constructs a lazy `T` instance, whose value, if needed, will later be /// obtained from `evaluator` and cached. /// /// `evaluator` will be invoked only the first time this instance /// is dereferenced or one of its methods is invoked. pub fn new(evaluator: Eval) -> Self { Self{ evaluator_cell: Cell::new(Some(evaluator)), value_cell: RefCell::new(None) } } /// Immutably borrows the evaluation result. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. /// /// **`value_ref()` will be removed in sloth 0.3.0. [`as_ref()` or immutable * dereference](struct.Lazy.html#implementations) should be used instead.** #[must_use] #[deprecated(since = "0.2.0", note = "will be removed in sloth 0.3.0; please use as_ref() or * deref operator instead")] pub fn value_ref(&self) -> Ref<'_, T> { self.init_once(); // Returns a Ref to the T instance contained within Option<T> referenced by value_cell Ref::map( self.value_cell.borrow(), |value_option| { value_option.as_ref().expect(EXPECT_VALUE_CELL_INITIALIZED) } ) } /// Mutably borrows the evaluation result. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. /// /// **`value_mut()` will be removed in sloth 0.3.0. [`as_mut()` or mutable * dereference](struct.Lazy.html#implementations) should be used instead.** #[must_use] #[deprecated(since = "0.2.0", note = "will be removed in sloth 0.3.0; please use as_mut() or * deref operator instead")] pub fn value_mut(&mut self) -> RefMut<'_, T> { self.init_once(); // Returns a RefMut to the T instance contained within Option<T> referenced by value_cell_mut RefMut::map( self.value_cell.borrow_mut(), |value_option| { value_option.as_mut().expect(EXPECT_VALUE_CELL_INITIALIZED) } ) } /// Consumes this [`Lazy<T, Eval>`](struct.Lazy.html) instance and extracts the evaluation result value. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. #[must_use] pub fn unwrap(self) -> T { self.init_once(); self.value_cell.replace(None).expect(EXPECT_VALUE_CELL_INITIALIZED) } // // Service // fn as_ref_impl(&self) -> &T { self.init_once(); unsafe { self.value_cell .as_ptr() .as_ref() .expect(EXPECT_VALUE_CELL_PTR_NOT_NULL) .as_ref() .expect(EXPECT_VALUE_CELL_INITIALIZED) } } fn as_mut_impl(&mut self) -> &mut T { self.init_once(); unsafe { self.value_cell .as_ptr() .as_mut() .expect(EXPECT_VALUE_CELL_PTR_NOT_NULL) .as_mut() .expect(EXPECT_VALUE_CELL_INITIALIZED) } } fn init_once(&self) { if self.value_cell.borrow().is_none() { *self.value_cell.borrow_mut() = Some(self.evaluate()); } } fn evaluate(&self) -> T { let evaluator = self.evaluator_cell .take() .expect(EXPECT_EVALUATOR_STILL_PRESENT); evaluator() } } impl<T, Eval> Lazy<T, Eval> where T: Copy, Eval: FnOnce() -> T { /// Returns a copy of the evaluation result. /// /// This will invoke evaluator function if none of the methods /// or `*` deref operator were previously used. #[must_use] pub fn value(&self) -> T { self.init_once(); self.value_cell.borrow().expect(EXPECT_VALUE_CELL_INITIALIZED) } }