|
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