@@ -164,6 +164,42 @@ impl<T> OnceCell<T> {
164164 }
165165 }
166166
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+
167203 /// Gets the contents of the cell, initializing it with `f` if
168204 /// the cell was empty. If the cell was empty and `f` failed, an
169205 /// error is returned.
@@ -200,16 +236,55 @@ impl<T> OnceCell<T> {
200236 if let Some ( val) = self . get ( ) {
201237 return Ok ( val) ;
202238 }
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) ?;
211276 }
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 ( ) ?;
213288 // Note that *some* forms of reentrant initialization might lead to
214289 // UB (see `reentrant_init` test). I believe that just removing this
215290 // `panic`, while keeping `try_insert` would be sound, but it seems
0 commit comments