core/cell/
lazy.rs

1use super::UnsafeCell;
2use crate::hint::unreachable_unchecked;
3use crate::ops::Deref;
4use crate::{fmt, mem};
5
6enum 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/// use std::cell::LazyCell;
22///
23/// let lazy: LazyCell<i32> = LazyCell::new(|| {
24///     println!("initializing");
25///     92
26/// });
27/// println!("ready");
28/// println!("{}", *lazy);
29/// println!("{}", *lazy);
30///
31/// // Prints:
32/// //   ready
33/// //   initializing
34/// //   92
35/// //   92
36/// ```
37#[stable(feature = "lazy_cell", since = "1.80.0")]
38pub struct LazyCell<T, F = fn() -> T> {
39    state: UnsafeCell<State<T, F>>,
40}
41
42impl<T, F: FnOnce() -> T> LazyCell<T, F> {
43    /// Creates a new lazy value with the given initializing function.
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// use std::cell::LazyCell;
49    ///
50    /// let hello = "Hello, World!".to_string();
51    ///
52    /// let lazy = LazyCell::new(|| hello.to_uppercase());
53    ///
54    /// assert_eq!(&*lazy, "HELLO, WORLD!");
55    /// ```
56    #[inline]
57    #[stable(feature = "lazy_cell", since = "1.80.0")]
58    #[rustc_const_stable(feature = "lazy_cell", since = "1.80.0")]
59    pub const fn new(f: F) -> LazyCell<T, F> {
60        LazyCell { state: UnsafeCell::new(State::Uninit(f)) }
61    }
62
63    /// Consumes this `LazyCell` returning the stored value.
64    ///
65    /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// #![feature(lazy_cell_into_inner)]
71    ///
72    /// use std::cell::LazyCell;
73    ///
74    /// let hello = "Hello, World!".to_string();
75    ///
76    /// let lazy = LazyCell::new(|| hello.to_uppercase());
77    ///
78    /// assert_eq!(&*lazy, "HELLO, WORLD!");
79    /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
80    /// ```
81    #[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
82    #[rustc_const_unstable(feature = "lazy_cell_into_inner", issue = "125623")]
83    pub const fn into_inner(this: Self) -> Result<T, F> {
84        match this.state.into_inner() {
85            State::Init(data) => Ok(data),
86            State::Uninit(f) => Err(f),
87            State::Poisoned => panic_poisoned(),
88        }
89    }
90
91    /// Forces the evaluation of this lazy value and returns a reference to
92    /// the result.
93    ///
94    /// This is equivalent to the `Deref` impl, but is explicit.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// use std::cell::LazyCell;
100    ///
101    /// let lazy = LazyCell::new(|| 92);
102    ///
103    /// assert_eq!(LazyCell::force(&lazy), &92);
104    /// assert_eq!(&*lazy, &92);
105    /// ```
106    #[inline]
107    #[stable(feature = "lazy_cell", since = "1.80.0")]
108    pub fn force(this: &LazyCell<T, F>) -> &T {
109        // SAFETY:
110        // This invalidates any mutable references to the data. The resulting
111        // reference lives either until the end of the borrow of `this` (in the
112        // initialized case) or is invalidated in `really_init` (in the
113        // uninitialized case; `really_init` will create and return a fresh reference).
114        let state = unsafe { &*this.state.get() };
115        match state {
116            State::Init(data) => data,
117            // SAFETY: The state is uninitialized.
118            State::Uninit(_) => unsafe { LazyCell::really_init(this) },
119            State::Poisoned => panic_poisoned(),
120        }
121    }
122
123    /// Forces the evaluation of this lazy value and returns a mutable reference to
124    /// the result.
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// #![feature(lazy_get)]
130    /// use std::cell::LazyCell;
131    ///
132    /// let mut lazy = LazyCell::new(|| 92);
133    ///
134    /// let p = LazyCell::force_mut(&mut lazy);
135    /// assert_eq!(*p, 92);
136    /// *p = 44;
137    /// assert_eq!(*lazy, 44);
138    /// ```
139    #[inline]
140    #[unstable(feature = "lazy_get", issue = "129333")]
141    pub fn force_mut(this: &mut LazyCell<T, F>) -> &mut T {
142        #[cold]
143        /// # Safety
144        /// May only be called when the state is `Uninit`.
145        unsafe fn really_init_mut<T, F: FnOnce() -> T>(state: &mut State<T, F>) -> &mut T {
146            // INVARIANT: Always valid, but the value may not be dropped.
147            struct PoisonOnPanic<T, F>(*mut State<T, F>);
148            impl<T, F> Drop for PoisonOnPanic<T, F> {
149                #[inline]
150                fn drop(&mut self) {
151                    // SAFETY: Invariant states it is valid, and we don't drop the old value.
152                    unsafe {
153                        self.0.write(State::Poisoned);
154                    }
155                }
156            }
157
158            let State::Uninit(f) = state else {
159                // `unreachable!()` here won't optimize out because the function is cold.
160                // SAFETY: Precondition.
161                unsafe { unreachable_unchecked() };
162            };
163            // SAFETY: We never drop the state after we read `f`, and we write a valid value back
164            // in any case, panic or success. `f` can't access the `LazyCell` because it is mutably
165            // borrowed.
166            let f = unsafe { core::ptr::read(f) };
167            // INVARIANT: Initiated from mutable reference, don't drop because we read it.
168            let guard = PoisonOnPanic(state);
169            let data = f();
170            // SAFETY: `PoisonOnPanic` invariant, and we don't drop the old value.
171            unsafe {
172                core::ptr::write(guard.0, State::Init(data));
173            }
174            core::mem::forget(guard);
175            let State::Init(data) = state else { unreachable!() };
176            data
177        }
178
179        let state = this.state.get_mut();
180        match state {
181            State::Init(data) => data,
182            // SAFETY: `state` is `Uninit`.
183            State::Uninit(_) => unsafe { really_init_mut(state) },
184            State::Poisoned => panic_poisoned(),
185        }
186    }
187
188    /// # Safety
189    /// May only be called when the state is `Uninit`.
190    #[cold]
191    unsafe fn really_init(this: &LazyCell<T, F>) -> &T {
192        // SAFETY:
193        // This function is only called when the state is uninitialized,
194        // so no references to `state` can exist except for the reference
195        // in `force`, which is invalidated here and not accessed again.
196        let state = unsafe { &mut *this.state.get() };
197        // Temporarily mark the state as poisoned. This prevents reentrant
198        // accesses and correctly poisons the cell if the closure panicked.
199        let State::Uninit(f) = mem::replace(state, State::Poisoned) else { unreachable!() };
200
201        let data = f();
202
203        // SAFETY:
204        // If the closure accessed the cell through something like a reentrant
205        // mutex, but caught the panic resulting from the state being poisoned,
206        // the mutable borrow for `state` will be invalidated, so we need to
207        // go through the `UnsafeCell` pointer here. The state can only be
208        // poisoned at this point, so using `write` to skip the destructor
209        // of `State` should help the optimizer.
210        unsafe { this.state.get().write(State::Init(data)) };
211
212        // SAFETY:
213        // The previous references were invalidated by the `write` call above,
214        // so do a new shared borrow of the state instead.
215        let state = unsafe { &*this.state.get() };
216        let State::Init(data) = state else { unreachable!() };
217        data
218    }
219}
220
221impl<T, F> LazyCell<T, F> {
222    /// Returns a mutable reference to the value if initialized, or `None` if not.
223    ///
224    /// # Examples
225    ///
226    /// ```
227    /// #![feature(lazy_get)]
228    ///
229    /// use std::cell::LazyCell;
230    ///
231    /// let mut lazy = LazyCell::new(|| 92);
232    ///
233    /// assert_eq!(LazyCell::get_mut(&mut lazy), None);
234    /// let _ = LazyCell::force(&lazy);
235    /// *LazyCell::get_mut(&mut lazy).unwrap() = 44;
236    /// assert_eq!(*lazy, 44);
237    /// ```
238    #[inline]
239    #[unstable(feature = "lazy_get", issue = "129333")]
240    pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {
241        let state = this.state.get_mut();
242        match state {
243            State::Init(data) => Some(data),
244            _ => None,
245        }
246    }
247
248    /// Returns a reference to the value if initialized, or `None` if not.
249    ///
250    /// # Examples
251    ///
252    /// ```
253    /// #![feature(lazy_get)]
254    ///
255    /// use std::cell::LazyCell;
256    ///
257    /// let lazy = LazyCell::new(|| 92);
258    ///
259    /// assert_eq!(LazyCell::get(&lazy), None);
260    /// let _ = LazyCell::force(&lazy);
261    /// assert_eq!(LazyCell::get(&lazy), Some(&92));
262    /// ```
263    #[inline]
264    #[unstable(feature = "lazy_get", issue = "129333")]
265    pub fn get(this: &LazyCell<T, F>) -> Option<&T> {
266        // SAFETY:
267        // This is sound for the same reason as in `force`: once the state is
268        // initialized, it will not be mutably accessed again, so this reference
269        // will stay valid for the duration of the borrow to `self`.
270        let state = unsafe { &*this.state.get() };
271        match state {
272            State::Init(data) => Some(data),
273            _ => None,
274        }
275    }
276}
277
278#[stable(feature = "lazy_cell", since = "1.80.0")]
279impl<T, F: FnOnce() -> T> Deref for LazyCell<T, F> {
280    type Target = T;
281    #[inline]
282    fn deref(&self) -> &T {
283        LazyCell::force(self)
284    }
285}
286
287#[stable(feature = "lazy_cell", since = "1.80.0")]
288impl<T: Default> Default for LazyCell<T> {
289    /// Creates a new lazy value using `Default` as the initializing function.
290    #[inline]
291    fn default() -> LazyCell<T> {
292        LazyCell::new(T::default)
293    }
294}
295
296#[stable(feature = "lazy_cell", since = "1.80.0")]
297impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> {
298    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299        let mut d = f.debug_tuple("LazyCell");
300        match LazyCell::get(self) {
301            Some(data) => d.field(data),
302            None => d.field(&format_args!("<uninit>")),
303        };
304        d.finish()
305    }
306}
307
308#[cold]
309#[inline(never)]
310const fn panic_poisoned() -> ! {
311    panic!("LazyCell instance has previously been poisoned")
312}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy