summaryrefslogtreecommitdiffstats
path: root/library/core/src/cell
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /library/core/src/cell
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/src/cell')
-rw-r--r--library/core/src/cell/once.rs46
1 files changed, 37 insertions, 9 deletions
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index 2e8534f65..3877a0c48 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -87,10 +87,40 @@ impl<T> OnceCell<T> {
#[inline]
#[stable(feature = "once_cell", since = "1.70.0")]
pub fn set(&self, value: T) -> Result<(), T> {
- // SAFETY: Safe because we cannot have overlapping mutable borrows
- let slot = unsafe { &*self.inner.get() };
- if slot.is_some() {
- return Err(value);
+ match self.try_insert(value) {
+ Ok(_) => Ok(()),
+ Err((_, value)) => Err(value),
+ }
+ }
+
+ /// Sets the contents of the cell to `value` if the cell was empty, then
+ /// returns a reference to it.
+ ///
+ /// # Errors
+ ///
+ /// This method returns `Ok(&value)` if the cell was empty and
+ /// `Err(&current_value, value)` if it was full.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(once_cell_try_insert)]
+ ///
+ /// use std::cell::OnceCell;
+ ///
+ /// let cell = OnceCell::new();
+ /// assert!(cell.get().is_none());
+ ///
+ /// assert_eq!(cell.try_insert(92), Ok(&92));
+ /// assert_eq!(cell.try_insert(62), Err((&92, 62)));
+ ///
+ /// assert!(cell.get().is_some());
+ /// ```
+ #[inline]
+ #[unstable(feature = "once_cell_try_insert", issue = "116693")]
+ pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
+ if let Some(old) = self.get() {
+ return Err((old, value));
}
// SAFETY: This is the only place where we set the slot, no races
@@ -98,8 +128,7 @@ impl<T> OnceCell<T> {
// checked that slot is currently `None`, so this write
// maintains the `inner`'s invariant.
let slot = unsafe { &mut *self.inner.get() };
- *slot = Some(value);
- Ok(())
+ Ok(slot.insert(value))
}
/// Gets the contents of the cell, initializing it with `f`
@@ -183,10 +212,9 @@ impl<T> OnceCell<T> {
let val = outlined_call(f)?;
// Note that *some* forms of reentrant initialization might lead to
// UB (see `reentrant_init` test). I believe that just removing this
- // `assert`, while keeping `set/get` would be sound, but it seems
+ // `panic`, while keeping `try_insert` would be sound, but it seems
// better to panic, rather than to silently use an old value.
- assert!(self.set(val).is_ok(), "reentrant init");
- Ok(self.get().unwrap())
+ if let Ok(val) = self.try_insert(val) { Ok(val) } else { panic!("reentrant init") }
}
/// Consumes the cell, returning the wrapped value.