@@ -2,6 +2,7 @@ use crate::cell::UnsafeCell;
22use crate::fmt;
33use crate::marker::PhantomData;
44use crate::mem::MaybeUninit;
5+ use crate::ops::{ControlFlow, FromResidual, Residual, Try};
56use crate::panic::{RefUnwindSafe, UnwindSafe};
67use crate::sync::Once;
78
@@ -173,8 +174,12 @@ impl<T> OnceLock<T> {
173174 }
174175
175176 /// Gets the contents of the cell, initializing it with `f` if
176- /// the cell was empty. If the cell was empty and `f` failed, an
177- /// error is returned.
177+ /// the cell was empty. If the cell was empty and `f` short-circuits,
178+ /// the residual value is returned.
179+ ///
180+ /// The return type of this method depends on the return type of the
181+ /// closure. If it returns `Result<T, E>`, the output is `Result<&T, E>`.
182+ /// If it returns `Option<T>`, the output is `Option<&T>`.
178183 ///
179184 /// # Panics
180185 ///
@@ -194,6 +199,7 @@ impl<T> OnceLock<T> {
194199 ///
195200 /// let cell = OnceLock::new();
196201 /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
202+ /// assert_eq!(cell.get_or_try_init(|| None), None);
197203 /// assert!(cell.get().is_none());
198204 /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
199205 /// Ok(92)
@@ -203,24 +209,30 @@ impl<T> OnceLock<T> {
203209 /// ```
204210 #[inline]
205211 #[unstable(feature = "once_cell_try", issue = "109737")]
206- pub fn get_or_try_init<F, E >(&self, f: F) -> Result<&T, E>
212+ pub fn get_or_try_init<'a, F, R >(&'a self, f: F) -> <R::Residual as Residual<&'a T>>::TryType
207213 where
208- F: FnOnce() -> Result<T, E>,
214+ F: FnOnce() -> R,
215+ R: Try<Output = T>,
216+ R::Residual: Residual<&'a T>,
209217 {
210218 // Fast path check
211219 // NOTE: We need to perform an acquire on the state in this method
212220 // in order to correctly synchronize `LazyLock::force`. This is
213221 // currently done by calling `self.get()`, which in turn calls
214222 // `self.is_initialized()`, which in turn performs the acquire.
215223 if let Some(value) = self.get() {
216- return Ok (value);
224+ return Try::from_output (value);
217225 }
218- self.initialize(f)?;
219226
220- debug_assert!(self.is_initialized());
227+ match self.initialize(f) {
228+ ControlFlow::Continue(()) => {
229+ debug_assert!(self.is_initialized());
221230
222- // SAFETY: The inner value has been initialized
223- Ok(unsafe { self.get_unchecked() })
231+ // SAFETY: The inner value has been initialized
232+ Try::from_output(unsafe { self.get_unchecked() })
233+ }
234+ ControlFlow::Break(residual) => FromResidual::from_residual(residual),
235+ }
224236 }
225237
226238 /// Consumes the `OnceLock`, returning the wrapped value. Returns
@@ -283,30 +295,31 @@ impl<T> OnceLock<T> {
283295 }
284296
285297 #[cold]
286- fn initialize<F, E >(&self, f: F) -> Result<(), E >
298+ fn initialize<F, R >(&self, f: F) -> ControlFlow<R::Residual >
287299 where
288- F: FnOnce() -> Result<T, E>,
300+ F: FnOnce() -> R,
301+ R: Try<Output = T>,
289302 {
290- let mut res: Result<(), E> = Ok (());
303+ let mut result = ControlFlow::Continue (());
291304 let slot = &self.value;
292305
293306 // Ignore poisoning from other threads
294307 // If another thread panics, then we'll be able to run our closure
295308 self.once.call_once_force(|p| {
296- match f() {
297- Ok (value) => {
309+ match f().branch() {
310+ ControlFlow::Continue (value) => {
298311 unsafe { (&mut *slot.get()).write(value) };
299312 }
300- Err(e ) => {
301- res = Err(e );
313+ ControlFlow::Break(residual ) => {
314+ result = ControlFlow::Break(residual );
302315
303316 // Treat the underlying `Once` as poisoned since we
304317 // failed to initialize our value. Calls
305318 p.poison();
306319 }
307320 }
308321 });
309- res
322+ result
310323 }
311324
312325 /// # Safety
0 commit comments