]> git.proxmox.com Git - rustc.git/blob - library/core/src/cell/once.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / library / core / src / cell / once.rs
1 use crate::cell::UnsafeCell;
2 use crate::fmt;
3 use crate::mem;
4
5 /// A cell which can be written to only once.
6 ///
7 /// Unlike [`RefCell`], a `OnceCell` only provides shared `&T` references to its value.
8 /// Unlike [`Cell`], a `OnceCell` doesn't require copying or replacing the value to access it.
9 ///
10 /// For a thread-safe version of this struct, see [`std::sync::OnceLock`].
11 ///
12 /// [`RefCell`]: crate::cell::RefCell
13 /// [`Cell`]: crate::cell::Cell
14 /// [`std::sync::OnceLock`]: ../../std/sync/struct.OnceLock.html
15 ///
16 /// # Examples
17 ///
18 /// ```
19 /// #![feature(once_cell)]
20 ///
21 /// use std::cell::OnceCell;
22 ///
23 /// let cell = OnceCell::new();
24 /// assert!(cell.get().is_none());
25 ///
26 /// let value: &String = cell.get_or_init(|| {
27 /// "Hello, World!".to_string()
28 /// });
29 /// assert_eq!(value, "Hello, World!");
30 /// assert!(cell.get().is_some());
31 /// ```
32 #[unstable(feature = "once_cell", issue = "74465")]
33 pub struct OnceCell<T> {
34 // Invariant: written to at most once.
35 inner: UnsafeCell<Option<T>>,
36 }
37
38 impl<T> OnceCell<T> {
39 /// Creates a new empty cell.
40 #[inline]
41 #[must_use]
42 #[unstable(feature = "once_cell", issue = "74465")]
43 pub const fn new() -> OnceCell<T> {
44 OnceCell { inner: UnsafeCell::new(None) }
45 }
46
47 /// Gets the reference to the underlying value.
48 ///
49 /// Returns `None` if the cell is empty.
50 #[inline]
51 #[unstable(feature = "once_cell", issue = "74465")]
52 pub fn get(&self) -> Option<&T> {
53 // SAFETY: Safe due to `inner`'s invariant
54 unsafe { &*self.inner.get() }.as_ref()
55 }
56
57 /// Gets the mutable reference to the underlying value.
58 ///
59 /// Returns `None` if the cell is empty.
60 #[inline]
61 #[unstable(feature = "once_cell", issue = "74465")]
62 pub fn get_mut(&mut self) -> Option<&mut T> {
63 self.inner.get_mut().as_mut()
64 }
65
66 /// Sets the contents of the cell to `value`.
67 ///
68 /// # Errors
69 ///
70 /// This method returns `Ok(())` if the cell was empty and `Err(value)` if
71 /// it was full.
72 ///
73 /// # Examples
74 ///
75 /// ```
76 /// #![feature(once_cell)]
77 ///
78 /// use std::cell::OnceCell;
79 ///
80 /// let cell = OnceCell::new();
81 /// assert!(cell.get().is_none());
82 ///
83 /// assert_eq!(cell.set(92), Ok(()));
84 /// assert_eq!(cell.set(62), Err(62));
85 ///
86 /// assert!(cell.get().is_some());
87 /// ```
88 #[inline]
89 #[unstable(feature = "once_cell", issue = "74465")]
90 pub fn set(&self, value: T) -> Result<(), T> {
91 // SAFETY: Safe because we cannot have overlapping mutable borrows
92 let slot = unsafe { &*self.inner.get() };
93 if slot.is_some() {
94 return Err(value);
95 }
96
97 // SAFETY: This is the only place where we set the slot, no races
98 // due to reentrancy/concurrency are possible, and we've
99 // checked that slot is currently `None`, so this write
100 // maintains the `inner`'s invariant.
101 let slot = unsafe { &mut *self.inner.get() };
102 *slot = Some(value);
103 Ok(())
104 }
105
106 /// Gets the contents of the cell, initializing it with `f`
107 /// if the cell was empty.
108 ///
109 /// # Panics
110 ///
111 /// If `f` panics, the panic is propagated to the caller, and the cell
112 /// remains uninitialized.
113 ///
114 /// It is an error to reentrantly initialize the cell from `f`. Doing
115 /// so results in a panic.
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// #![feature(once_cell)]
121 ///
122 /// use std::cell::OnceCell;
123 ///
124 /// let cell = OnceCell::new();
125 /// let value = cell.get_or_init(|| 92);
126 /// assert_eq!(value, &92);
127 /// let value = cell.get_or_init(|| unreachable!());
128 /// assert_eq!(value, &92);
129 /// ```
130 #[inline]
131 #[unstable(feature = "once_cell", issue = "74465")]
132 pub fn get_or_init<F>(&self, f: F) -> &T
133 where
134 F: FnOnce() -> T,
135 {
136 match self.get_or_try_init(|| Ok::<T, !>(f())) {
137 Ok(val) => val,
138 }
139 }
140
141 /// Gets the contents of the cell, initializing it with `f` if
142 /// the cell was empty. If the cell was empty and `f` failed, an
143 /// error is returned.
144 ///
145 /// # Panics
146 ///
147 /// If `f` panics, the panic is propagated to the caller, and the cell
148 /// remains uninitialized.
149 ///
150 /// It is an error to reentrantly initialize the cell from `f`. Doing
151 /// so results in a panic.
152 ///
153 /// # Examples
154 ///
155 /// ```
156 /// #![feature(once_cell)]
157 ///
158 /// use std::cell::OnceCell;
159 ///
160 /// let cell = OnceCell::new();
161 /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
162 /// assert!(cell.get().is_none());
163 /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
164 /// Ok(92)
165 /// });
166 /// assert_eq!(value, Ok(&92));
167 /// assert_eq!(cell.get(), Some(&92))
168 /// ```
169 #[unstable(feature = "once_cell", issue = "74465")]
170 pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
171 where
172 F: FnOnce() -> Result<T, E>,
173 {
174 if let Some(val) = self.get() {
175 return Ok(val);
176 }
177 /// Avoid inlining the initialization closure into the common path that fetches
178 /// the already initialized value
179 #[cold]
180 fn outlined_call<F, T, E>(f: F) -> Result<T, E>
181 where
182 F: FnOnce() -> Result<T, E>,
183 {
184 f()
185 }
186 let val = outlined_call(f)?;
187 // Note that *some* forms of reentrant initialization might lead to
188 // UB (see `reentrant_init` test). I believe that just removing this
189 // `assert`, while keeping `set/get` would be sound, but it seems
190 // better to panic, rather than to silently use an old value.
191 assert!(self.set(val).is_ok(), "reentrant init");
192 Ok(self.get().unwrap())
193 }
194
195 /// Consumes the cell, returning the wrapped value.
196 ///
197 /// Returns `None` if the cell was empty.
198 ///
199 /// # Examples
200 ///
201 /// ```
202 /// #![feature(once_cell)]
203 ///
204 /// use std::cell::OnceCell;
205 ///
206 /// let cell: OnceCell<String> = OnceCell::new();
207 /// assert_eq!(cell.into_inner(), None);
208 ///
209 /// let cell = OnceCell::new();
210 /// cell.set("hello".to_string()).unwrap();
211 /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
212 /// ```
213 #[inline]
214 #[unstable(feature = "once_cell", issue = "74465")]
215 pub fn into_inner(self) -> Option<T> {
216 // Because `into_inner` takes `self` by value, the compiler statically verifies
217 // that it is not currently borrowed. So it is safe to move out `Option<T>`.
218 self.inner.into_inner()
219 }
220
221 /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
222 ///
223 /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
224 ///
225 /// Safety is guaranteed by requiring a mutable reference.
226 ///
227 /// # Examples
228 ///
229 /// ```
230 /// #![feature(once_cell)]
231 ///
232 /// use std::cell::OnceCell;
233 ///
234 /// let mut cell: OnceCell<String> = OnceCell::new();
235 /// assert_eq!(cell.take(), None);
236 ///
237 /// let mut cell = OnceCell::new();
238 /// cell.set("hello".to_string()).unwrap();
239 /// assert_eq!(cell.take(), Some("hello".to_string()));
240 /// assert_eq!(cell.get(), None);
241 /// ```
242 #[inline]
243 #[unstable(feature = "once_cell", issue = "74465")]
244 pub fn take(&mut self) -> Option<T> {
245 mem::take(self).into_inner()
246 }
247 }
248
249 #[unstable(feature = "once_cell", issue = "74465")]
250 impl<T> Default for OnceCell<T> {
251 #[inline]
252 fn default() -> Self {
253 Self::new()
254 }
255 }
256
257 #[unstable(feature = "once_cell", issue = "74465")]
258 impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
259 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260 match self.get() {
261 Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
262 None => f.write_str("OnceCell(Uninit)"),
263 }
264 }
265 }
266
267 #[unstable(feature = "once_cell", issue = "74465")]
268 impl<T: Clone> Clone for OnceCell<T> {
269 #[inline]
270 fn clone(&self) -> OnceCell<T> {
271 let res = OnceCell::new();
272 if let Some(value) = self.get() {
273 match res.set(value.clone()) {
274 Ok(()) => (),
275 Err(_) => unreachable!(),
276 }
277 }
278 res
279 }
280 }
281
282 #[unstable(feature = "once_cell", issue = "74465")]
283 impl<T: PartialEq> PartialEq for OnceCell<T> {
284 #[inline]
285 fn eq(&self, other: &Self) -> bool {
286 self.get() == other.get()
287 }
288 }
289
290 #[unstable(feature = "once_cell", issue = "74465")]
291 impl<T: Eq> Eq for OnceCell<T> {}
292
293 #[unstable(feature = "once_cell", issue = "74465")]
294 impl<T> const From<T> for OnceCell<T> {
295 /// Creates a new `OnceCell<T>` which already contains the given `value`.
296 #[inline]
297 fn from(value: T) -> Self {
298 OnceCell { inner: UnsafeCell::new(Some(value)) }
299 }
300 }