• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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