|
1 | 1 | use crate::cell::UnsafeCell;
|
| 2 | +use crate::ops::{ControlFlow, FromResidual, Residual, Try}; |
2 | 3 | use crate::{fmt, mem};
|
3 | 4 |
|
4 | 5 | /// A cell which can nominally be written to only once.
|
@@ -228,14 +229,18 @@ impl<T> OnceCell<T> {
|
228 | 229 | /// assert_eq!(cell.get(), Some(&92))
|
229 | 230 | /// ```
|
230 | 231 | #[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 |
232 | 233 | where
|
233 |
| - F: FnOnce() -> Result<T, E>, |
| 234 | + F: FnOnce() -> R, |
| 235 | + R: Try<Output = T, Residual: Residual<&'a T>>, |
234 | 236 | {
|
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 | + } |
237 | 241 | }
|
238 |
| - self.try_init(f) |
| 242 | + |
| 243 | + try { self.get().unwrap() } |
239 | 244 | }
|
240 | 245 |
|
241 | 246 | /// Gets the mutable reference of the contents of the cell, initializing
|
@@ -266,29 +271,40 @@ impl<T> OnceCell<T> {
|
266 | 271 | /// assert_eq!(cell.get(), Some(&1236))
|
267 | 272 | /// ```
|
268 | 273 | #[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 |
270 | 278 | where
|
271 |
| - F: FnOnce() -> Result<T, E>, |
| 279 | + F: FnOnce() -> R, |
| 280 | + R: Try<Output = T, Residual: Residual<&'a mut T>>, |
272 | 281 | {
|
273 | 282 | 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 | + } |
275 | 286 | }
|
276 |
| - Ok(self.get_mut().unwrap()) |
| 287 | + |
| 288 | + try { self.get_mut().unwrap() } |
277 | 289 | }
|
278 | 290 |
|
279 | 291 | // Avoid inlining the initialization closure into the common path that fetches
|
280 | 292 | // the already initialized value
|
281 | 293 | #[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, ()> |
283 | 295 | where
|
284 |
| - F: FnOnce() -> Result<T, E>, |
| 296 | + F: FnOnce() -> R, |
| 297 | + R: Try<Output = T>, |
285 | 298 | {
|
286 |
| - let val = f()?; |
| 299 | + let val = f().branch()?; |
287 | 300 | // Note that *some* forms of reentrant initialization might lead to
|
288 | 301 | // UB (see `reentrant_init` test). I believe that just removing this
|
289 | 302 | // `panic`, while keeping `try_insert` would be sound, but it seems
|
290 | 303 | // 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 | + } |
292 | 308 | }
|
293 | 309 |
|
294 | 310 | /// Consumes the cell, returning the wrapped value.
|
|
0 commit comments