xref: /third_party/rust/crates/lazycell/src/lib.rs (revision f6121a04)
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