Skip to content

Commit 9668ea0

Browse files
committed
core: use Try trait to make OnceCell::get_or_try_init generic over result type
1 parent ddccc26 commit 9668ea0

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

library/core/src/cell/once.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::cell::UnsafeCell;
2+
use crate::ops::{ControlFlow, FromResidual, Residual, Try};
23
use crate::{fmt, mem};
34

45
/// A cell which can nominally be written to only once.
@@ -228,14 +229,18 @@ impl<T> OnceCell<T> {
228229
/// assert_eq!(cell.get(), Some(&92))
229230
/// ```
230231
#[unstable(feature = "once_cell_try", issue = "109737")]
231-
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
232+
pub fn get_or_try_init<'a, F, R>(&'a self, f: F) -> <R::Residual as Residual<&'a T>>::TryType
232233
where
233-
F: FnOnce() -> Result<T, E>,
234+
F: FnOnce() -> R,
235+
R: Try<Output = T, Residual: Residual<&'a T>>,
234236
{
235-
if let Some(val) = self.get() {
236-
return Ok(val);
237+
if self.get().is_none() {
238+
if let ControlFlow::Break(residual) = self.try_init(f) {
239+
return FromResidual::from_residual(residual);
240+
}
237241
}
238-
self.try_init(f)
242+
243+
try { self.get().unwrap() }
239244
}
240245

241246
/// Gets the mutable reference of the contents of the cell, initializing
@@ -266,29 +271,40 @@ impl<T> OnceCell<T> {
266271
/// assert_eq!(cell.get(), Some(&1236))
267272
/// ```
268273
#[unstable(feature = "once_cell_get_mut", issue = "121641")]
269-
pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E>
274+
pub fn get_mut_or_try_init<'a, F, R>(
275+
&'a mut self,
276+
f: F,
277+
) -> <R::Residual as Residual<&'a mut T>>::TryType
270278
where
271-
F: FnOnce() -> Result<T, E>,
279+
F: FnOnce() -> R,
280+
R: Try<Output = T, Residual: Residual<&'a mut T>>,
272281
{
273282
if self.get().is_none() {
274-
self.try_init(f)?;
283+
if let ControlFlow::Break(residual) = self.try_init(f) {
284+
return FromResidual::from_residual(residual);
285+
}
275286
}
276-
Ok(self.get_mut().unwrap())
287+
288+
try { self.get_mut().unwrap() }
277289
}
278290

279291
// Avoid inlining the initialization closure into the common path that fetches
280292
// the already initialized value
281293
#[cold]
282-
fn try_init<F, E>(&self, f: F) -> Result<&T, E>
294+
fn try_init<F, R>(&self, f: F) -> ControlFlow<R::Residual, ()>
283295
where
284-
F: FnOnce() -> Result<T, E>,
296+
F: FnOnce() -> R,
297+
R: Try<Output = T>,
285298
{
286-
let val = f()?;
299+
let val = f().branch()?;
287300
// Note that *some* forms of reentrant initialization might lead to
288301
// UB (see `reentrant_init` test). I believe that just removing this
289302
// `panic`, while keeping `try_insert` would be sound, but it seems
290303
// better to panic, rather than to silently use an old value.
291-
if let Ok(val) = self.try_insert(val) { Ok(val) } else { panic!("reentrant init") }
304+
match self.try_insert(val) {
305+
Ok(_) => ControlFlow::Continue(()),
306+
Err(_) => panic!("reentrant init"),
307+
}
292308
}
293309

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

0 commit comments

Comments
 (0)