@@ -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