1 // Original work Copyright (c) 2014 The Rust Project Developers 2 // Modified work Copyright (c) 2016-2018 Nikita Pekin and the lazycell contributors 3 // See the README.md file at the top-level directory of this distribution. 4 // 5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 8 // option. This file may not be copied, modified, or distributed 9 // except according to those terms. 10 11 #![cfg_attr(not(test), no_std)] 12 13 #![deny(missing_docs)] 14 #![cfg_attr(feature = "nightly", feature(plugin))] 15 #![cfg_attr(feature = "clippy", plugin(clippy))] 16 17 //! This crate provides a `LazyCell` struct which acts as a lazily filled 18 //! `Cell`. 19 //! 20 //! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of 21 //! the entire object, but only of the borrows returned. A `LazyCell` is a 22 //! variation on `RefCell` which allows borrows to be tied to the lifetime of 23 //! the outer object. 24 //! 25 //! # Example 26 //! 27 //! The following example shows a quick example of the basic functionality of 28 //! `LazyCell`. 29 //! 30 //! ``` 31 //! use lazycell::LazyCell; 32 //! 33 //! let lazycell = LazyCell::new(); 34 //! 35 //! assert_eq!(lazycell.borrow(), None); 36 //! assert!(!lazycell.filled()); 37 //! lazycell.fill(1).ok(); 38 //! assert!(lazycell.filled()); 39 //! assert_eq!(lazycell.borrow(), Some(&1)); 40 //! assert_eq!(lazycell.into_inner(), Some(1)); 41 //! ``` 42 //! 43 //! `AtomicLazyCell` is a variant that uses an atomic variable to manage 44 //! coordination in a thread-safe fashion. The limitation of an `AtomicLazyCell` 45 //! is that after it is initialized, it can't be modified. 46 47 48 #[cfg(not(test))] 49 #[macro_use] 50 extern crate core as std; 51 52 use std::cell::UnsafeCell; 53 use std::mem; 54 use std::sync::atomic::{AtomicUsize, Ordering}; 55 56 /// A lazily filled `Cell`, with mutable contents. 57 /// 58 /// A `LazyCell` is completely frozen once filled, **unless** you have `&mut` 59 /// access to it, in which case `LazyCell::borrow_mut` may be used to mutate the 60 /// contents. 61 #[derive(Debug, Default)] 62 pub struct LazyCell<T> { 63 inner: UnsafeCell<Option<T>>, 64 } 65 66 impl<T> LazyCell<T> { 67 /// Creates a new, empty, `LazyCell`. new() -> LazyCell<T>68 pub fn new() -> LazyCell<T> { 69 LazyCell { inner: UnsafeCell::new(None) } 70 } 71 72 /// Put a value into this cell. 73 /// 74 /// This function will return `Err(value)` is the cell is already full. fill(&self, value: T) -> Result<(), T>75 pub fn fill(&self, value: T) -> Result<(), T> { 76 let slot = unsafe { &mut *self.inner.get() }; 77 if slot.is_some() { 78 return Err(value); 79 } 80 *slot = Some(value); 81 82 Ok(()) 83 } 84 85 /// Put a value into this cell. 86 /// 87 /// Note that this function is infallible but requires `&mut self`. By 88 /// requiring `&mut self` we're guaranteed that no active borrows to this 89 /// cell can exist so we can always fill in the value. This may not always 90 /// be usable, however, as `&mut self` may not be possible to borrow. 91 /// 92 /// # Return value 93 /// 94 /// This function returns the previous value, if any. replace(&mut self, value: T) -> Option<T>95 pub fn replace(&mut self, value: T) -> Option<T> { 96 mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) 97 } 98 99 /// Test whether this cell has been previously filled. filled(&self) -> bool100 pub fn filled(&self) -> bool { 101 self.borrow().is_some() 102 } 103 104 /// Borrows the contents of this lazy cell for the duration of the cell 105 /// itself. 106 /// 107 /// This function will return `Some` if the cell has been previously 108 /// initialized, and `None` if it has not yet been initialized. borrow(&self) -> Option<&T>109 pub fn borrow(&self) -> Option<&T> { 110 unsafe { &*self.inner.get() }.as_ref() 111 } 112 113 /// Borrows the contents of this lazy cell mutably for the duration of the cell 114 /// itself. 115 /// 116 /// This function will return `Some` if the cell has been previously 117 /// initialized, and `None` if it has not yet been initialized. borrow_mut(&mut self) -> Option<&mut T>118 pub fn borrow_mut(&mut self) -> Option<&mut T> { 119 unsafe { &mut *self.inner.get() }.as_mut() 120 } 121 122 /// Borrows the contents of this lazy cell for the duration of the cell 123 /// itself. 124 /// 125 /// If the cell has not yet been filled, the cell is first filled using the 126 /// function provided. 127 /// 128 /// # Panics 129 /// 130 /// Panics if the cell becomes filled as a side effect of `f`. borrow_with<F: FnOnce() -> T>(&self, f: F) -> &T131 pub fn borrow_with<F: FnOnce() -> T>(&self, f: F) -> &T { 132 if let Some(value) = self.borrow() { 133 return value; 134 } 135 let value = f(); 136 if self.fill(value).is_err() { 137 panic!("borrow_with: cell was filled by closure") 138 } 139 self.borrow().unwrap() 140 } 141 142 /// Borrows the contents of this `LazyCell` mutably for the duration of the 143 /// cell itself. 144 /// 145 /// If the cell has not yet been filled, the cell is first filled using the 146 /// function provided. 147 /// 148 /// # Panics 149 /// 150 /// Panics if the cell becomes filled as a side effect of `f`. borrow_mut_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T151 pub fn borrow_mut_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T { 152 if !self.filled() { 153 let value = f(); 154 if self.fill(value).is_err() { 155 panic!("borrow_mut_with: cell was filled by closure") 156 } 157 } 158 159 self.borrow_mut().unwrap() 160 } 161 162 /// Same as `borrow_with`, but allows the initializing function to fail. 163 /// 164 /// # Panics 165 /// 166 /// Panics if the cell becomes filled as a side effect of `f`. try_borrow_with<E, F>(&self, f: F) -> Result<&T, E> where F: FnOnce() -> Result<T, E>167 pub fn try_borrow_with<E, F>(&self, f: F) -> Result<&T, E> 168 where F: FnOnce() -> Result<T, E> 169 { 170 if let Some(value) = self.borrow() { 171 return Ok(value); 172 } 173 let value = f()?; 174 if self.fill(value).is_err() { 175 panic!("try_borrow_with: cell was filled by closure") 176 } 177 Ok(self.borrow().unwrap()) 178 } 179 180 /// Same as `borrow_mut_with`, but allows the initializing function to fail. 181 /// 182 /// # Panics 183 /// 184 /// Panics if the cell becomes filled as a side effect of `f`. try_borrow_mut_with<E, F>(&mut self, f: F) -> Result<&mut T, E> where F: FnOnce() -> Result<T, E>185 pub fn try_borrow_mut_with<E, F>(&mut self, f: F) -> Result<&mut T, E> 186 where F: FnOnce() -> Result<T, E> 187 { 188 if self.filled() { 189 return Ok(self.borrow_mut().unwrap()); 190 } 191 let value = f()?; 192 if self.fill(value).is_err() { 193 panic!("try_borrow_mut_with: cell was filled by closure") 194 } 195 Ok(self.borrow_mut().unwrap()) 196 } 197 198 /// Consumes this `LazyCell`, returning the underlying value. into_inner(self) -> Option<T>199 pub fn into_inner(self) -> Option<T> { 200 // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe 201 // function. This unsafe can be removed when supporting Rust older than 202 // 1.25 is not needed. 203 #[allow(unused_unsafe)] 204 unsafe { self.inner.into_inner() } 205 } 206 } 207 208 impl<T: Copy> LazyCell<T> { 209 /// Returns a copy of the contents of the lazy cell. 210 /// 211 /// This function will return `Some` if the cell has been previously initialized, 212 /// and `None` if it has not yet been initialized. get(&self) -> Option<T>213 pub fn get(&self) -> Option<T> { 214 unsafe { *self.inner.get() } 215 } 216 } 217 218 impl <T: Clone> Clone for LazyCell<T> { 219 /// Create a clone of this `LazyCell` 220 /// 221 /// If self has not been initialized, returns an uninitialized `LazyCell` 222 /// otherwise returns a `LazyCell` already initialized with a clone of the 223 /// contents of self. clone(&self) -> LazyCell<T>224 fn clone(&self) -> LazyCell<T> { 225 LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) } 226 } 227 } 228 229 // Tracks the AtomicLazyCell inner state 230 const NONE: usize = 0; 231 const LOCK: usize = 1; 232 const SOME: usize = 2; 233 234 /// A lazily filled and thread-safe `Cell`, with frozen contents. 235 #[derive(Debug, Default)] 236 pub struct AtomicLazyCell<T> { 237 inner: UnsafeCell<Option<T>>, 238 state: AtomicUsize, 239 } 240 241 impl<T> AtomicLazyCell<T> { 242 /// An empty `AtomicLazyCell`. 243 pub const NONE: Self = Self { 244 inner: UnsafeCell::new(None), 245 state: AtomicUsize::new(NONE), 246 }; 247 248 /// Creates a new, empty, `AtomicLazyCell`. new() -> AtomicLazyCell<T>249 pub fn new() -> AtomicLazyCell<T> { 250 Self::NONE 251 } 252 253 /// Put a value into this cell. 254 /// 255 /// This function will return `Err(value)` is the cell is already full. fill(&self, t: T) -> Result<(), T>256 pub fn fill(&self, t: T) -> Result<(), T> { 257 if NONE != self.state.compare_and_swap(NONE, LOCK, Ordering::Acquire) { 258 return Err(t); 259 } 260 261 unsafe { *self.inner.get() = Some(t) }; 262 263 if LOCK != self.state.compare_and_swap(LOCK, SOME, Ordering::Release) { 264 panic!("unable to release lock"); 265 } 266 267 Ok(()) 268 } 269 270 /// Put a value into this cell. 271 /// 272 /// Note that this function is infallible but requires `&mut self`. By 273 /// requiring `&mut self` we're guaranteed that no active borrows to this 274 /// cell can exist so we can always fill in the value. This may not always 275 /// be usable, however, as `&mut self` may not be possible to borrow. 276 /// 277 /// # Return value 278 /// 279 /// This function returns the previous value, if any. replace(&mut self, value: T) -> Option<T>280 pub fn replace(&mut self, value: T) -> Option<T> { 281 match mem::replace(self.state.get_mut(), SOME) { 282 NONE | SOME => {} 283 _ => panic!("cell in inconsistent state"), 284 } 285 mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) 286 } 287 288 /// Test whether this cell has been previously filled. filled(&self) -> bool289 pub fn filled(&self) -> bool { 290 self.state.load(Ordering::Acquire) == SOME 291 } 292 293 /// Borrows the contents of this lazy cell for the duration of the cell 294 /// itself. 295 /// 296 /// This function will return `Some` if the cell has been previously 297 /// initialized, and `None` if it has not yet been initialized. borrow(&self) -> Option<&T>298 pub fn borrow(&self) -> Option<&T> { 299 match self.state.load(Ordering::Acquire) { 300 SOME => unsafe { &*self.inner.get() }.as_ref(), 301 _ => None, 302 } 303 } 304 305 /// Consumes this `LazyCell`, returning the underlying value. into_inner(self) -> Option<T>306 pub fn into_inner(self) -> Option<T> { 307 // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe 308 // function. This unsafe can be removed when supporting Rust older than 309 // 1.25 is not needed. 310 #[allow(unused_unsafe)] 311 unsafe { self.inner.into_inner() } 312 } 313 } 314 315 impl<T: Copy> AtomicLazyCell<T> { 316 /// Returns a copy of the contents of the lazy cell. 317 /// 318 /// This function will return `Some` if the cell has been previously initialized, 319 /// and `None` if it has not yet been initialized. get(&self) -> Option<T>320 pub fn get(&self) -> Option<T> { 321 match self.state.load(Ordering::Acquire) { 322 SOME => unsafe { *self.inner.get() }, 323 _ => None, 324 } 325 } 326 } 327 328 impl<T: Clone> Clone for AtomicLazyCell<T> { 329 /// Create a clone of this `AtomicLazyCell` 330 /// 331 /// If self has not been initialized, returns an uninitialized `AtomicLazyCell` 332 /// otherwise returns an `AtomicLazyCell` already initialized with a clone of the 333 /// contents of self. clone(&self) -> AtomicLazyCell<T>334 fn clone(&self) -> AtomicLazyCell<T> { 335 self.borrow().map_or( 336 Self::NONE, 337 |v| AtomicLazyCell { 338 inner: UnsafeCell::new(Some(v.clone())), 339 state: AtomicUsize::new(SOME), 340 } 341 ) 342 } 343 } 344 345 unsafe impl<T: Sync + Send> Sync for AtomicLazyCell<T> {} 346 347 unsafe impl<T: Send> Send for AtomicLazyCell<T> {} 348 349 #[cfg(test)] 350 mod tests { 351 use super::{AtomicLazyCell, LazyCell}; 352 353 #[test] test_borrow_from_empty()354 fn test_borrow_from_empty() { 355 let lazycell: LazyCell<usize> = LazyCell::new(); 356 357 let value = lazycell.borrow(); 358 assert_eq!(value, None); 359 360 let value = lazycell.get(); 361 assert_eq!(value, None); 362 } 363 364 #[test] test_fill_and_borrow()365 fn test_fill_and_borrow() { 366 let lazycell = LazyCell::new(); 367 368 assert!(!lazycell.filled()); 369 lazycell.fill(1).unwrap(); 370 assert!(lazycell.filled()); 371 372 let value = lazycell.borrow(); 373 assert_eq!(value, Some(&1)); 374 375 let value = lazycell.get(); 376 assert_eq!(value, Some(1)); 377 } 378 379 #[test] test_borrow_mut()380 fn test_borrow_mut() { 381 let mut lazycell = LazyCell::new(); 382 assert!(lazycell.borrow_mut().is_none()); 383 384 lazycell.fill(1).unwrap(); 385 assert_eq!(lazycell.borrow_mut(), Some(&mut 1)); 386 387 *lazycell.borrow_mut().unwrap() = 2; 388 assert_eq!(lazycell.borrow_mut(), Some(&mut 2)); 389 390 // official way to reset the cell 391 lazycell = LazyCell::new(); 392 assert!(lazycell.borrow_mut().is_none()); 393 } 394 395 #[test] test_already_filled_error()396 fn test_already_filled_error() { 397 let lazycell = LazyCell::new(); 398 399 lazycell.fill(1).unwrap(); 400 assert_eq!(lazycell.fill(1), Err(1)); 401 } 402 403 #[test] test_borrow_with()404 fn test_borrow_with() { 405 let lazycell = LazyCell::new(); 406 407 let value = lazycell.borrow_with(|| 1); 408 assert_eq!(&1, value); 409 } 410 411 #[test] test_borrow_with_already_filled()412 fn test_borrow_with_already_filled() { 413 let lazycell = LazyCell::new(); 414 lazycell.fill(1).unwrap(); 415 416 let value = lazycell.borrow_with(|| 1); 417 assert_eq!(&1, value); 418 } 419 420 #[test] test_borrow_with_not_called_when_filled()421 fn test_borrow_with_not_called_when_filled() { 422 let lazycell = LazyCell::new(); 423 424 lazycell.fill(1).unwrap(); 425 426 let value = lazycell.borrow_with(|| 2); 427 assert_eq!(&1, value); 428 } 429 430 #[test] 431 #[should_panic] test_borrow_with_sound_with_reentrancy()432 fn test_borrow_with_sound_with_reentrancy() { 433 // Kudos to dbaupp for discovering this issue 434 // https://www.reddit.com/r/rust/comments/5vs9rt/lazycell_a_rust_library_providing_a_lazilyfilled/de527xm/ 435 let lazycell: LazyCell<Box<i32>> = LazyCell::new(); 436 437 let mut reference: Option<&i32> = None; 438 439 lazycell.borrow_with(|| { 440 let _ = lazycell.fill(Box::new(1)); 441 reference = lazycell.borrow().map(|r| &**r); 442 Box::new(2) 443 }); 444 } 445 446 #[test] test_borrow_mut_with()447 fn test_borrow_mut_with() { 448 let mut lazycell = LazyCell::new(); 449 450 { 451 let value = lazycell.borrow_mut_with(|| 1); 452 assert_eq!(&mut 1, value); 453 *value = 2; 454 } 455 assert_eq!(&2, lazycell.borrow().unwrap()); 456 } 457 458 #[test] test_borrow_mut_with_already_filled()459 fn test_borrow_mut_with_already_filled() { 460 let mut lazycell = LazyCell::new(); 461 lazycell.fill(1).unwrap(); 462 463 let value = lazycell.borrow_mut_with(|| 1); 464 assert_eq!(&1, value); 465 } 466 467 #[test] test_borrow_mut_with_not_called_when_filled()468 fn test_borrow_mut_with_not_called_when_filled() { 469 let mut lazycell = LazyCell::new(); 470 471 lazycell.fill(1).unwrap(); 472 473 let value = lazycell.borrow_mut_with(|| 2); 474 assert_eq!(&1, value); 475 } 476 477 #[test] test_try_borrow_with_ok()478 fn test_try_borrow_with_ok() { 479 let lazycell = LazyCell::new(); 480 let result = lazycell.try_borrow_with::<(), _>(|| Ok(1)); 481 assert_eq!(result, Ok(&1)); 482 } 483 484 #[test] test_try_borrow_with_err()485 fn test_try_borrow_with_err() { 486 let lazycell = LazyCell::<()>::new(); 487 let result = lazycell.try_borrow_with(|| Err(1)); 488 assert_eq!(result, Err(1)); 489 } 490 491 #[test] test_try_borrow_with_already_filled()492 fn test_try_borrow_with_already_filled() { 493 let lazycell = LazyCell::new(); 494 lazycell.fill(1).unwrap(); 495 let result = lazycell.try_borrow_with::<(), _>(|| unreachable!()); 496 assert_eq!(result, Ok(&1)); 497 } 498 499 #[test] 500 #[should_panic] test_try_borrow_with_sound_with_reentrancy()501 fn test_try_borrow_with_sound_with_reentrancy() { 502 let lazycell: LazyCell<Box<i32>> = LazyCell::new(); 503 504 let mut reference: Option<&i32> = None; 505 506 let _ = lazycell.try_borrow_with::<(), _>(|| { 507 let _ = lazycell.fill(Box::new(1)); 508 reference = lazycell.borrow().map(|r| &**r); 509 Ok(Box::new(2)) 510 }); 511 } 512 513 #[test] test_try_borrow_mut_with_ok()514 fn test_try_borrow_mut_with_ok() { 515 let mut lazycell = LazyCell::new(); 516 { 517 let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1)); 518 assert_eq!(result, Ok(&mut 1)); 519 *result.unwrap() = 2; 520 } 521 assert_eq!(&mut 2, lazycell.borrow().unwrap()); 522 } 523 524 #[test] test_try_borrow_mut_with_err()525 fn test_try_borrow_mut_with_err() { 526 let mut lazycell = LazyCell::<()>::new(); 527 let result = lazycell.try_borrow_mut_with(|| Err(1)); 528 assert_eq!(result, Err(1)); 529 } 530 531 #[test] test_try_borrow_mut_with_already_filled()532 fn test_try_borrow_mut_with_already_filled() { 533 let mut lazycell = LazyCell::new(); 534 lazycell.fill(1).unwrap(); 535 let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!()); 536 assert_eq!(result, Ok(&mut 1)); 537 } 538 539 #[test] test_into_inner()540 fn test_into_inner() { 541 let lazycell = LazyCell::new(); 542 543 lazycell.fill(1).unwrap(); 544 let value = lazycell.into_inner(); 545 assert_eq!(value, Some(1)); 546 } 547 548 #[test] test_atomic_borrow_from_empty()549 fn test_atomic_borrow_from_empty() { 550 let lazycell: AtomicLazyCell<usize> = AtomicLazyCell::new(); 551 552 let value = lazycell.borrow(); 553 assert_eq!(value, None); 554 555 let value = lazycell.get(); 556 assert_eq!(value, None); 557 } 558 559 #[test] test_atomic_fill_and_borrow()560 fn test_atomic_fill_and_borrow() { 561 let lazycell = AtomicLazyCell::new(); 562 563 assert!(!lazycell.filled()); 564 lazycell.fill(1).unwrap(); 565 assert!(lazycell.filled()); 566 567 let value = lazycell.borrow(); 568 assert_eq!(value, Some(&1)); 569 570 let value = lazycell.get(); 571 assert_eq!(value, Some(1)); 572 } 573 574 #[test] test_atomic_already_filled_panic()575 fn test_atomic_already_filled_panic() { 576 let lazycell = AtomicLazyCell::new(); 577 578 lazycell.fill(1).unwrap(); 579 assert_eq!(1, lazycell.fill(1).unwrap_err()); 580 } 581 582 #[test] test_atomic_into_inner()583 fn test_atomic_into_inner() { 584 let lazycell = AtomicLazyCell::new(); 585 586 lazycell.fill(1).unwrap(); 587 let value = lazycell.into_inner(); 588 assert_eq!(value, Some(1)); 589 } 590 591 #[test] normal_replace()592 fn normal_replace() { 593 let mut cell = LazyCell::new(); 594 assert_eq!(cell.fill(1), Ok(())); 595 assert_eq!(cell.replace(2), Some(1)); 596 assert_eq!(cell.replace(3), Some(2)); 597 assert_eq!(cell.borrow(), Some(&3)); 598 599 let mut cell = LazyCell::new(); 600 assert_eq!(cell.replace(2), None); 601 } 602 603 #[test] atomic_replace()604 fn atomic_replace() { 605 let mut cell = AtomicLazyCell::new(); 606 assert_eq!(cell.fill(1), Ok(())); 607 assert_eq!(cell.replace(2), Some(1)); 608 assert_eq!(cell.replace(3), Some(2)); 609 assert_eq!(cell.borrow(), Some(&3)); 610 } 611 612 #[test] clone()613 fn clone() { 614 let mut cell = LazyCell::new(); 615 let clone1 = cell.clone(); 616 assert_eq!(clone1.borrow(), None); 617 assert_eq!(cell.fill(1), Ok(())); 618 let mut clone2 = cell.clone(); 619 assert_eq!(clone1.borrow(), None); 620 assert_eq!(clone2.borrow(), Some(&1)); 621 assert_eq!(cell.replace(2), Some(1)); 622 assert_eq!(clone1.borrow(), None); 623 assert_eq!(clone2.borrow(), Some(&1)); 624 assert_eq!(clone1.fill(3), Ok(())); 625 assert_eq!(clone2.replace(4), Some(1)); 626 assert_eq!(clone1.borrow(), Some(&3)); 627 assert_eq!(clone2.borrow(), Some(&4)); 628 assert_eq!(cell.borrow(), Some(&2)); 629 } 630 631 #[test] clone_atomic()632 fn clone_atomic() { 633 let mut cell = AtomicLazyCell::new(); 634 let clone1 = cell.clone(); 635 assert_eq!(clone1.borrow(), None); 636 assert_eq!(cell.fill(1), Ok(())); 637 let mut clone2 = cell.clone(); 638 assert_eq!(clone1.borrow(), None); 639 assert_eq!(clone2.borrow(), Some(&1)); 640 assert_eq!(cell.replace(2), Some(1)); 641 assert_eq!(clone1.borrow(), None); 642 assert_eq!(clone2.borrow(), Some(&1)); 643 assert_eq!(clone1.fill(3), Ok(())); 644 assert_eq!(clone2.replace(4), Some(1)); 645 assert_eq!(clone1.borrow(), Some(&3)); 646 assert_eq!(clone2.borrow(), Some(&4)); 647 assert_eq!(cell.borrow(), Some(&2)); 648 } 649 } 650