1use core::fmt;
4use core::ops::Deref;
5
6use super::once_cell::OnceCell;
7
8pub struct Lazy<T, F = fn() -> T> {
23 cell: OnceCell<T>,
24 init: F,
25}
26
27impl<T, F> Lazy<T, F> {
28 loom_const_fn! {
29 pub fn new(init: F) -> Self {
31 Self { cell: OnceCell::new(), init }
32 }
33 }
34}
35
36impl<T, F: Fn() -> T> Lazy<T, F> {
37 pub fn force(this: &Self) -> &T {
39 this.cell.get_or_init_racy(|| (this.init)())
40 }
41}
42
43impl<T, F: Fn() -> T> Deref for Lazy<T, F> {
44 type Target = T;
45
46 fn deref(&self) -> &T {
47 Self::force(self)
48 }
49}
50
51impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 f.debug_tuple("Lazy").field(&self.cell.get()).finish()
54 }
55}
56
57#[cfg(all(test, not(loom)))]
58mod tests {
59 use super::*;
60 use std::cell::Cell;
61
62 #[test]
63 fn the_value_is_built_on_first_use_and_kept() {
64 let calls = Cell::new(0);
65 let lazy = Lazy::new(|| {
66 calls.set(calls.get() + 1);
67 vec![1, 2, 3]
68 });
69 assert_eq!(calls.get(), 0);
70 assert_eq!(lazy.len(), 3);
71 assert_eq!(*Lazy::force(&lazy), vec![1, 2, 3]);
72 assert_eq!(calls.get(), 1);
73 }
74}