@@ -164,6 +164,42 @@ impl<T> OnceCell<T> {
164
164
}
165
165
}
166
166
167
+ /// Gets the mutable reference of the contents of the cell,
168
+ /// initializing it with `f` if the cell was empty.
169
+ ///
170
+ /// # Panics
171
+ ///
172
+ /// If `f` panics, the panic is propagated to the caller, and the cell
173
+ /// remains uninitialized.
174
+ ///
175
+ /// # Examples
176
+ ///
177
+ /// ```
178
+ /// #![feature(once_cell_get_mut)]
179
+ ///
180
+ /// use std::cell::OnceCell;
181
+ ///
182
+ /// let mut cell = OnceCell::new();
183
+ /// let value = cell.get_mut_or_init(|| 92);
184
+ /// assert_eq!(*value, 92);
185
+ ///
186
+ /// *value += 2;
187
+ /// assert_eq!(*value, 94);
188
+ ///
189
+ /// let value = cell.get_mut_or_init(|| unreachable!());
190
+ /// assert_eq!(*value, 94);
191
+ /// ```
192
+ #[ inline]
193
+ #[ unstable( feature = "once_cell_get_mut" , issue = "121641" ) ]
194
+ pub fn get_mut_or_init < F > ( & mut self , f : F ) -> & mut T
195
+ where
196
+ F : FnOnce ( ) -> T ,
197
+ {
198
+ match self . get_mut_or_try_init ( || Ok :: < T , !> ( f ( ) ) ) {
199
+ Ok ( val) => val,
200
+ }
201
+ }
202
+
167
203
/// Gets the contents of the cell, initializing it with `f` if
168
204
/// the cell was empty. If the cell was empty and `f` failed, an
169
205
/// error is returned.
@@ -200,16 +236,55 @@ impl<T> OnceCell<T> {
200
236
if let Some ( val) = self . get ( ) {
201
237
return Ok ( val) ;
202
238
}
203
- /// Avoid inlining the initialization closure into the common path that fetches
204
- /// the already initialized value
205
- #[ cold]
206
- fn outlined_call < F , T , E > ( f : F ) -> Result < T , E >
207
- where
208
- F : FnOnce ( ) -> Result < T , E > ,
209
- {
210
- f ( )
239
+ self . try_init ( f)
240
+ }
241
+
242
+ /// Gets the mutable reference of the contents of the cell, initializing
243
+ /// it with `f` if the cell was empty. If the cell was empty and `f` failed,
244
+ /// an error is returned.
245
+ ///
246
+ /// # Panics
247
+ ///
248
+ /// If `f` panics, the panic is propagated to the caller, and the cell
249
+ /// remains uninitialized.
250
+ ///
251
+ /// # Examples
252
+ ///
253
+ /// ```
254
+ /// #![feature(once_cell_get_mut)]
255
+ ///
256
+ /// use std::cell::OnceCell;
257
+ ///
258
+ /// let mut cell: OnceCell<u32> = OnceCell::new();
259
+ ///
260
+ /// // Failed initializers do not change the value
261
+ /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err());
262
+ /// assert!(cell.get().is_none());
263
+ ///
264
+ /// let value = cell.get_mut_or_try_init(|| "1234".parse());
265
+ /// assert_eq!(value, Ok(&mut 1234));
266
+ /// *value.unwrap() += 2;
267
+ /// assert_eq!(cell.get(), Some(&1236))
268
+ /// ```
269
+ #[ unstable( feature = "once_cell_get_mut" , issue = "121641" ) ]
270
+ pub fn get_mut_or_try_init < F , E > ( & mut self , f : F ) -> Result < & mut T , E >
271
+ where
272
+ F : FnOnce ( ) -> Result < T , E > ,
273
+ {
274
+ if self . get ( ) . is_none ( ) {
275
+ self . try_init ( f) ?;
211
276
}
212
- let val = outlined_call ( f) ?;
277
+ Ok ( self . get_mut ( ) . unwrap ( ) )
278
+ }
279
+
280
+ // Avoid inlining the initialization closure into the common path that fetches
281
+ // the already initialized value
282
+ #[ cold]
283
+ fn try_init < F , E > ( & self , f : F ) -> Result < & T , E >
284
+ where
285
+ F : FnOnce ( ) -> Result < T , E > ,
286
+ {
287
+ let val = f ( ) ?;
213
288
// Note that *some* forms of reentrant initialization might lead to
214
289
// UB (see `reentrant_init` test). I believe that just removing this
215
290
// `panic`, while keeping `try_insert` would be sound, but it seems
0 commit comments