Skip to content

Commit e1d6a1a

Browse files
committed
Implement OnceCell/Lock::try_insert()
1 parent bf9a1c8 commit e1d6a1a

File tree

2 files changed

+71
-8
lines changed

2 files changed

+71
-8
lines changed

library/core/src/cell/once.rs

+33-5
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,38 @@ impl<T> OnceCell<T> {
8787
#[inline]
8888
#[stable(feature = "once_cell", since = "1.70.0")]
8989
pub fn set(&self, value: T) -> Result<(), T> {
90-
// SAFETY: Safe because we cannot have overlapping mutable borrows
91-
let slot = unsafe { &*self.inner.get() };
92-
if slot.is_some() {
93-
return Err(value);
90+
match self.try_insert(value) {
91+
Ok(_) => Ok(()),
92+
Err((_, value)) => Err(value),
93+
}
94+
}
95+
96+
/// Sets the contents of the cell to `value` if the cell was empty, then
97+
/// returns a reference to it.
98+
///
99+
/// # Errors
100+
///
101+
/// This method returns `Ok(&value)` if the cell was empty and
102+
/// `Err(&current_value, value)` if it was full.
103+
///
104+
/// # Examples
105+
///
106+
/// ```
107+
/// use std::cell::OnceCell;
108+
///
109+
/// let cell = OnceCell::new();
110+
/// assert!(cell.get().is_none());
111+
///
112+
/// assert_eq!(cell.try_insert(92), Ok(&92));
113+
/// assert_eq!(cell.try_insert(62), Err((&92, 62)));
114+
///
115+
/// assert!(cell.get().is_some());
116+
/// ```
117+
#[inline]
118+
#[unstable(feature = "once_cell_try_insert", issue = "116693")]
119+
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
120+
if let Some(old) = self.get() {
121+
return Err((old, value));
94122
}
95123

96124
// SAFETY: This is the only place where we set the slot, no races
@@ -99,7 +127,7 @@ impl<T> OnceCell<T> {
99127
// maintains the `inner`'s invariant.
100128
let slot = unsafe { &mut *self.inner.get() };
101129
*slot = Some(value);
102-
Ok(())
130+
Ok(self.get().unwrap())
103131
}
104132

105133
/// Gets the contents of the cell, initializing it with `f`

library/std/src/sync/once_lock.rs

+38-3
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,46 @@ impl<T> OnceLock<T> {
126126
#[inline]
127127
#[stable(feature = "once_cell", since = "1.70.0")]
128128
pub fn set(&self, value: T) -> Result<(), T> {
129+
match self.try_insert(value) {
130+
Ok(_) => Ok(()),
131+
Err((_, value)) => Err(value),
132+
}
133+
}
134+
135+
/// Sets the contents of this cell to `value` if the cell was empty, then
136+
/// returns a reference to it.
137+
///
138+
/// May block if another thread is currently attempting to initialize the cell. The cell is
139+
/// guaranteed to contain a value when set returns, though not necessarily the one provided.
140+
///
141+
/// Returns `Ok(&value)` if the cell was empty and `Err(&current_value, value)` if it was full.
142+
///
143+
/// # Examples
144+
///
145+
/// ```
146+
/// use std::sync::OnceLock;
147+
///
148+
/// static CELL: OnceLock<i32> = OnceLock::new();
149+
///
150+
/// fn main() {
151+
/// assert!(CELL.get().is_none());
152+
///
153+
/// std::thread::spawn(|| {
154+
/// assert_eq!(CELL.try_insert(92), Ok(&92));
155+
/// }).join().unwrap();
156+
///
157+
/// assert_eq!(CELL.try_insert(62), Err((&92, 62)));
158+
/// assert_eq!(CELL.get(), Some(&92));
159+
/// }
160+
/// ```
161+
#[inline]
162+
#[unstable(feature = "once_cell_try_insert", issue = "116693")]
163+
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
129164
let mut value = Some(value);
130-
self.get_or_init(|| value.take().unwrap());
165+
let res = self.get_or_init(|| value.take().unwrap());
131166
match value {
132-
None => Ok(()),
133-
Some(value) => Err(value),
167+
None => Ok(res),
168+
Some(value) => Err((res, value)),
134169
}
135170
}
136171

0 commit comments

Comments
 (0)