Skip to content

Commit c681c8b

Browse files
committed
impl get_mut_or_init and get_mut_or_try_init for OnceCell
See also rust-lang#74465 (comment) Signed-off-by: tison <wander4096@gmail.com>
1 parent e81522a commit c681c8b

File tree

1 file changed

+33
-10
lines changed

1 file changed

+33
-10
lines changed

library/core/src/cell/once.rs

+33-10
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ impl<T> OnceCell<T> {
135135
}
136136
}
137137

138+
#[inline]
139+
pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T
140+
where
141+
F: FnOnce() -> T,
142+
{
143+
match self.get_mut_or_try_init(|| Ok::<T, !>(f())) {
144+
Ok(val) => val,
145+
}
146+
}
147+
138148
/// Gets the contents of the cell, initializing it with `f` if
139149
/// the cell was empty. If the cell was empty and `f` failed, an
140150
/// error is returned.
@@ -171,22 +181,35 @@ impl<T> OnceCell<T> {
171181
if let Some(val) = self.get() {
172182
return Ok(val);
173183
}
174-
/// Avoid inlining the initialization closure into the common path that fetches
175-
/// the already initialized value
176-
#[cold]
177-
fn outlined_call<F, T, E>(f: F) -> Result<T, E>
178-
where
179-
F: FnOnce() -> Result<T, E>,
180-
{
181-
f()
184+
self.try_init(f)?;
185+
Ok(self.get().unwrap())
186+
}
187+
188+
pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E>
189+
where
190+
F: FnOnce() -> Result<T, E>,
191+
{
192+
if let Some(val) = self.get() {
193+
return Ok(val);
182194
}
183-
let val = outlined_call(f)?;
195+
self.try_init(f)?;
196+
Ok(self.get_mut().unwrap())
197+
}
198+
199+
// Avoid inlining the initialization closure into the common path that fetches
200+
// the already initialized value
201+
#[cold]
202+
fn try_init<F, E>(&self, f: F) -> Result<(), E>
203+
where
204+
F: FnOnce() -> Result<T, E>,
205+
{
206+
let val = f()?;
184207
// Note that *some* forms of reentrant initialization might lead to
185208
// UB (see `reentrant_init` test). I believe that just removing this
186209
// `assert`, while keeping `set/get` would be sound, but it seems
187210
// better to panic, rather than to silently use an old value.
188211
assert!(self.set(val).is_ok(), "reentrant init");
189-
Ok(self.get().unwrap())
212+
Ok(())
190213
}
191214

192215
/// Consumes the cell, returning the wrapped value.

0 commit comments

Comments
 (0)