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