1 | use crate::ops::Deref; |
2 | use crate::{fmt, mem}; |
3 | |
4 | use super::UnsafeCell; |
5 | |
6 | enum State<T, F> { |
7 | Uninit(F), |
8 | Init(T), |
9 | Poisoned, |
10 | } |
11 | |
12 | /// A value which is initialized on the first access. |
13 | /// |
14 | /// For a thread-safe version of this struct, see [`std::sync::LazyLock`]. |
15 | /// |
16 | /// [`std::sync::LazyLock`]: ../../std/sync/struct.LazyLock.html |
17 | /// |
18 | /// # Examples |
19 | /// |
20 | /// ``` |
21 | /// #![feature(lazy_cell)] |
22 | /// |
23 | /// use std::cell::LazyCell; |
24 | /// |
25 | /// let lazy: LazyCell<i32> = LazyCell::new(|| { |
26 | /// println!("initializing" ); |
27 | /// 92 |
28 | /// }); |
29 | /// println!("ready" ); |
30 | /// println!("{}" , *lazy); |
31 | /// println!("{}" , *lazy); |
32 | /// |
33 | /// // Prints: |
34 | /// // ready |
35 | /// // initializing |
36 | /// // 92 |
37 | /// // 92 |
38 | /// ``` |
39 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
40 | pub struct LazyCell<T, F = fn() -> T> { |
41 | state: UnsafeCell<State<T, F>>, |
42 | } |
43 | |
44 | impl<T, F: FnOnce() -> T> LazyCell<T, F> { |
45 | /// Creates a new lazy value with the given initializing function. |
46 | /// |
47 | /// # Examples |
48 | /// |
49 | /// ``` |
50 | /// #![feature(lazy_cell)] |
51 | /// |
52 | /// use std::cell::LazyCell; |
53 | /// |
54 | /// let hello = "Hello, World!" .to_string(); |
55 | /// |
56 | /// let lazy = LazyCell::new(|| hello.to_uppercase()); |
57 | /// |
58 | /// assert_eq!(&*lazy, "HELLO, WORLD!" ); |
59 | /// ``` |
60 | #[inline ] |
61 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
62 | pub const fn new(f: F) -> LazyCell<T, F> { |
63 | LazyCell { state: UnsafeCell::new(State::Uninit(f)) } |
64 | } |
65 | |
66 | /// Consumes this `LazyCell` returning the stored value. |
67 | /// |
68 | /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. |
69 | /// |
70 | /// # Examples |
71 | /// |
72 | /// ``` |
73 | /// #![feature(lazy_cell)] |
74 | /// #![feature(lazy_cell_consume)] |
75 | /// |
76 | /// use std::cell::LazyCell; |
77 | /// |
78 | /// let hello = "Hello, World!" .to_string(); |
79 | /// |
80 | /// let lazy = LazyCell::new(|| hello.to_uppercase()); |
81 | /// |
82 | /// assert_eq!(&*lazy, "HELLO, WORLD!" ); |
83 | /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!" .to_string())); |
84 | /// ``` |
85 | #[unstable (feature = "lazy_cell_consume" , issue = "109736" )] |
86 | pub fn into_inner(this: Self) -> Result<T, F> { |
87 | match this.state.into_inner() { |
88 | State::Init(data) => Ok(data), |
89 | State::Uninit(f) => Err(f), |
90 | State::Poisoned => panic!("LazyCell instance has previously been poisoned" ), |
91 | } |
92 | } |
93 | |
94 | /// Forces the evaluation of this lazy value and returns a reference to |
95 | /// the result. |
96 | /// |
97 | /// This is equivalent to the `Deref` impl, but is explicit. |
98 | /// |
99 | /// # Examples |
100 | /// |
101 | /// ``` |
102 | /// #![feature(lazy_cell)] |
103 | /// |
104 | /// use std::cell::LazyCell; |
105 | /// |
106 | /// let lazy = LazyCell::new(|| 92); |
107 | /// |
108 | /// assert_eq!(LazyCell::force(&lazy), &92); |
109 | /// assert_eq!(&*lazy, &92); |
110 | /// ``` |
111 | #[inline ] |
112 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
113 | pub fn force(this: &LazyCell<T, F>) -> &T { |
114 | // SAFETY: |
115 | // This invalidates any mutable references to the data. The resulting |
116 | // reference lives either until the end of the borrow of `this` (in the |
117 | // initialized case) or is invalidated in `really_init` (in the |
118 | // uninitialized case; `really_init` will create and return a fresh reference). |
119 | let state = unsafe { &*this.state.get() }; |
120 | match state { |
121 | State::Init(data) => data, |
122 | // SAFETY: The state is uninitialized. |
123 | State::Uninit(_) => unsafe { LazyCell::really_init(this) }, |
124 | State::Poisoned => panic!("LazyCell has previously been poisoned" ), |
125 | } |
126 | } |
127 | |
128 | /// # Safety |
129 | /// May only be called when the state is `Uninit`. |
130 | #[cold ] |
131 | unsafe fn really_init(this: &LazyCell<T, F>) -> &T { |
132 | // SAFETY: |
133 | // This function is only called when the state is uninitialized, |
134 | // so no references to `state` can exist except for the reference |
135 | // in `force`, which is invalidated here and not accessed again. |
136 | let state = unsafe { &mut *this.state.get() }; |
137 | // Temporarily mark the state as poisoned. This prevents reentrant |
138 | // accesses and correctly poisons the cell if the closure panicked. |
139 | let State::Uninit(f) = mem::replace(state, State::Poisoned) else { unreachable!() }; |
140 | |
141 | let data = f(); |
142 | |
143 | // SAFETY: |
144 | // If the closure accessed the cell through something like a reentrant |
145 | // mutex, but caught the panic resulting from the state being poisoned, |
146 | // the mutable borrow for `state` will be invalidated, so we need to |
147 | // go through the `UnsafeCell` pointer here. The state can only be |
148 | // poisoned at this point, so using `write` to skip the destructor |
149 | // of `State` should help the optimizer. |
150 | unsafe { this.state.get().write(State::Init(data)) }; |
151 | |
152 | // SAFETY: |
153 | // The previous references were invalidated by the `write` call above, |
154 | // so do a new shared borrow of the state instead. |
155 | let state = unsafe { &*this.state.get() }; |
156 | let State::Init(data) = state else { unreachable!() }; |
157 | data |
158 | } |
159 | } |
160 | |
161 | impl<T, F> LazyCell<T, F> { |
162 | #[inline ] |
163 | fn get(&self) -> Option<&T> { |
164 | // SAFETY: |
165 | // This is sound for the same reason as in `force`: once the state is |
166 | // initialized, it will not be mutably accessed again, so this reference |
167 | // will stay valid for the duration of the borrow to `self`. |
168 | let state: &State = unsafe { &*self.state.get() }; |
169 | match state { |
170 | State::Init(data: &T) => Some(data), |
171 | _ => None, |
172 | } |
173 | } |
174 | } |
175 | |
176 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
177 | impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> { |
178 | type Target = T; |
179 | #[inline ] |
180 | fn deref(&self) -> &T { |
181 | LazyCell::force(self) |
182 | } |
183 | } |
184 | |
185 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
186 | impl<T: Default> Default for LazyCell<T> { |
187 | /// Creates a new lazy value using `Default` as the initializing function. |
188 | #[inline ] |
189 | fn default() -> LazyCell<T> { |
190 | LazyCell::new(T::default) |
191 | } |
192 | } |
193 | |
194 | #[unstable (feature = "lazy_cell" , issue = "109736" )] |
195 | impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> { |
196 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
197 | let mut d: DebugTuple<'_, '_> = f.debug_tuple(name:"LazyCell" ); |
198 | match self.get() { |
199 | Some(data: &T) => d.field(data), |
200 | None => d.field(&format_args!("<uninit>" )), |
201 | }; |
202 | d.finish() |
203 | } |
204 | } |
205 | |