Skip to content

Commit 0790d34

Browse files
committed
feat: impl get_mut_or_init and get_mut_or_try_init for OnceLock
Signed-off-by: tison <[email protected]>
1 parent 03bad24 commit 0790d34

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

library/std/src/sync/once_lock.rs

+97
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,50 @@ impl<T> OnceLock<T> {
252252
}
253253
}
254254

255+
/// Gets the mutable reference of the contents of the cell, initializing
256+
/// it with `f` if the cell was empty.
257+
///
258+
/// Many threads may call `get_mut_or_init` concurrently with different
259+
/// initializing functions, but it is guaranteed that only one function
260+
/// will be executed.
261+
///
262+
/// # Panics
263+
///
264+
/// If `f` panics, the panic is propagated to the caller, and the cell
265+
/// remains uninitialized.
266+
///
267+
/// It is an error to reentrantly initialize the cell from `f`. The
268+
/// exact outcome is unspecified. Current implementation deadlocks, but
269+
/// this may be changed to a panic in the future.
270+
///
271+
/// # Examples
272+
///
273+
/// ```
274+
/// #![feature(once_cell_get_mut)]
275+
///
276+
/// use std::sync::OnceLock;
277+
///
278+
/// let mut cell = OnceLock::new();
279+
/// let value = cell.get_mut_or_init(|| 92);
280+
/// assert_eq!(*value, 92);
281+
///
282+
/// *value += 2;
283+
/// assert_eq!(*value, 94);
284+
///
285+
/// let value = cell.get_mut_or_init(|| unreachable!());
286+
/// assert_eq!(*value, 94);
287+
/// ```
288+
#[inline]
289+
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
290+
pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T
291+
where
292+
F: FnOnce() -> T,
293+
{
294+
match self.get_mut_or_try_init(|| Ok::<T, !>(f())) {
295+
Ok(val) => val,
296+
}
297+
}
298+
255299
/// Gets the contents of the cell, initializing it with `f` if
256300
/// the cell was empty. If the cell was empty and `f` failed, an
257301
/// error is returned.
@@ -303,6 +347,59 @@ impl<T> OnceLock<T> {
303347
Ok(unsafe { self.get_unchecked() })
304348
}
305349

350+
/// Gets the mutable reference of the contents of the cell, initializing
351+
/// it with `f` if the cell was empty. If the cell was empty and `f` failed,
352+
/// an error is returned.
353+
///
354+
/// # Panics
355+
///
356+
/// If `f` panics, the panic is propagated to the caller, and
357+
/// the cell remains uninitialized.
358+
///
359+
/// It is an error to reentrantly initialize the cell from `f`.
360+
/// The exact outcome is unspecified. Current implementation
361+
/// deadlocks, but this may be changed to a panic in the future.
362+
///
363+
/// # Examples
364+
///
365+
/// ```
366+
/// #![feature(once_cell_get_mut)]
367+
///
368+
/// use std::sync::OnceLock;
369+
///
370+
/// let mut cell: OnceLock<u32> = OnceLock::new();
371+
///
372+
/// // Failed initializers do not change the value
373+
/// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err());
374+
/// assert!(cell.get().is_none());
375+
///
376+
/// let value = cell.get_mut_or_try_init(|| "1234".parse());
377+
/// assert_eq!(value, Ok(&mut 1234));
378+
/// *value.unwrap() += 2;
379+
/// assert_eq!(cell.get(), Some(&1236))
380+
/// ```
381+
#[inline]
382+
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
383+
pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E>
384+
where
385+
F: FnOnce() -> Result<T, E>,
386+
{
387+
// Fast path check
388+
// NOTE: We need to perform an acquire on the state in this method
389+
// in order to correctly synchronize `LazyLock::force`. This is
390+
// currently done by calling `self.get()`, which in turn calls
391+
// `self.is_initialized()`, which in turn performs the acquire.
392+
if let Some(value) = self.get_mut() {
393+
return Ok(value);
394+
}
395+
self.initialize(f)?;
396+
397+
debug_assert!(self.is_initialized());
398+
399+
// SAFETY: The inner value has been initialized
400+
Ok(unsafe { self.get_unchecked_mut() })
401+
}
402+
306403
/// Consumes the `OnceLock`, returning the wrapped value. Returns
307404
/// `None` if the cell was empty.
308405
///

0 commit comments

Comments
 (0)