@@ -87,19 +87,48 @@ impl<T> OnceCell<T> {
87
87
#[ inline]
88
88
#[ stable( feature = "once_cell" , since = "1.70.0" ) ]
89
89
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) ) ;
94
124
}
95
125
96
126
// SAFETY: This is the only place where we set the slot, no races
97
127
// due to reentrancy/concurrency are possible, and we've
98
128
// checked that slot is currently `None`, so this write
99
129
// maintains the `inner`'s invariant.
100
130
let slot = unsafe { & mut * self . inner . get ( ) } ;
101
- * slot = Some ( value) ;
102
- Ok ( ( ) )
131
+ Ok ( slot. insert ( value) )
103
132
}
104
133
105
134
/// Gets the contents of the cell, initializing it with `f`
@@ -183,10 +212,9 @@ impl<T> OnceCell<T> {
183
212
let val = outlined_call ( f) ?;
184
213
// Note that *some* forms of reentrant initialization might lead to
185
214
// 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
187
216
// 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" ) }
190
218
}
191
219
192
220
/// Consumes the cell, returning the wrapped value.
0 commit comments