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] 50extern crate core as std; 51 52use std::cell::UnsafeCell; 53use std::mem; 54use 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)] 62pub struct LazyCell<T> { 63 inner: UnsafeCell<Option<T>>, 64} 65 66impl<T> LazyCell<T> { 67 /// Creates a new, empty, `LazyCell`. 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. 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. 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. 100 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. 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. 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`. 131 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`. 151 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`. 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`. 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. 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 208impl<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. 213 pub fn get(&self) -> Option<T> { 214 unsafe { *self.inner.get() } 215 } 216} 217 218impl <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. 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 230const NONE: usize = 0; 231const LOCK: usize = 1; 232const SOME: usize = 2; 233 234/// A lazily filled and thread-safe `Cell`, with frozen contents. 235#[derive(Debug, Default)] 236pub struct AtomicLazyCell<T> { 237 inner: UnsafeCell<Option<T>>, 238 state: AtomicUsize, 239} 240 241impl<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`. 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. 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. 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. 289 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. 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. 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 315impl<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. 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 328impl<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. 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 345unsafe impl<T: Sync + Send> Sync for AtomicLazyCell<T> {} 346 347unsafe impl<T: Send> Send for AtomicLazyCell<T> {} 348 349#[cfg(test)] 350mod tests { 351 use super::{AtomicLazyCell, LazyCell}; 352 353 #[test] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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