blob: f7f8488a5252b5ae8f1407f153591bb99e8b3ad0 [file] [log] [blame]
Chih-Hung Hsiehde83b092020-04-07 14:24:01 -07001// 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}