1use crate::ops::Deref;
2use crate::{fmt, mem};
3
4use super::UnsafeCell;
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/// #![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")]
40pub struct LazyCell<T, F = fn() -> T> {
41 state: UnsafeCell<State<T, F>>,
42}
43
44impl<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
161impl<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")]
177impl<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")]
186impl<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")]
195impl<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