]> git.lizzy.rs Git - rust.git/blob - library/core/src/cell/once.rs
Auto merge of #106307 - Nilstrieb:dynamic->static, r=cjgillot
[rust.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 }