@@ -87,19 +87,48 @@ impl<T> OnceCell<T> {
8787 #[ inline]
8888 #[ stable( feature = "once_cell" , since = "1.70.0" ) ]
8989 pub fn set ( & self , value : T ) -> Result < ( ) , T > {
90- // SAFETY: Safe because we cannot have overlapping mutable borrows
91- let slot = unsafe { & * self . inner . get ( ) } ;
92- if slot. is_some ( ) {
93- return Err ( value) ;
90+ match self . try_insert ( value) {
91+ Ok ( _) => Ok ( ( ) ) ,
92+ Err ( ( _, value) ) => Err ( value) ,
93+ }
94+ }
95+
96+ /// Sets the contents of the cell to `value` if the cell was empty, then
97+ /// returns a reference to it.
98+ ///
99+ /// # Errors
100+ ///
101+ /// This method returns `Ok(&value)` if the cell was empty and
102+ /// `Err(¤t_value, value)` if it was full.
103+ ///
104+ /// # Examples
105+ ///
106+ /// ```
107+ /// #![feature(once_cell_try_insert)]
108+ ///
109+ /// use std::cell::OnceCell;
110+ ///
111+ /// let cell = OnceCell::new();
112+ /// assert!(cell.get().is_none());
113+ ///
114+ /// assert_eq!(cell.try_insert(92), Ok(&92));
115+ /// assert_eq!(cell.try_insert(62), Err((&92, 62)));
116+ ///
117+ /// assert!(cell.get().is_some());
118+ /// ```
119+ #[ inline]
120+ #[ unstable( feature = "once_cell_try_insert" , issue = "116693" ) ]
121+ pub fn try_insert ( & self , value : T ) -> Result < & T , ( & T , T ) > {
122+ if let Some ( old) = self . get ( ) {
123+ return Err ( ( old, value) ) ;
94124 }
95125
96126 // SAFETY: This is the only place where we set the slot, no races
97127 // due to reentrancy/concurrency are possible, and we've
98128 // checked that slot is currently `None`, so this write
99129 // maintains the `inner`'s invariant.
100130 let slot = unsafe { & mut * self . inner . get ( ) } ;
101- * slot = Some ( value) ;
102- Ok ( ( ) )
131+ Ok ( slot. insert ( value) )
103132 }
104133
105134 /// Gets the contents of the cell, initializing it with `f`
@@ -183,10 +212,9 @@ impl<T> OnceCell<T> {
183212 let val = outlined_call ( f) ?;
184213 // Note that *some* forms of reentrant initialization might lead to
185214 // UB (see `reentrant_init` test). I believe that just removing this
186- // `assert `, while keeping `set/get ` would be sound, but it seems
215+ // `panic `, while keeping `try_insert ` would be sound, but it seems
187216 // better to panic, rather than to silently use an old value.
188- assert ! ( self . set( val) . is_ok( ) , "reentrant init" ) ;
189- Ok ( self . get ( ) . unwrap ( ) )
217+ if let Ok ( val) = self . try_insert ( val) { Ok ( val) } else { panic ! ( "reentrant init" ) }
190218 }
191219
192220 /// Consumes the cell, returning the wrapped value.
0 commit comments