@@ -42,7 +42,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
42
42
/// tokio::spawn(async move { second_cl.set(10) });
43
43
///
44
44
/// let res = arc.get(); // returns None
45
- ///
46
45
/// arc.wait().await; // lets wait until the value is set
47
46
///
48
47
/// println!("{:?}", arc.get());
@@ -53,38 +52,21 @@ use std::sync::atomic::{AtomicBool, Ordering};
53
52
/// initialized once on first use, but need no further changes. The `SetOnce`
54
53
/// in Tokio allows the initialization procedure to be asynchronous.
55
54
///
56
- /// # Examples
55
+ /// # Example
57
56
///
58
57
/// ```
59
- /// use tokio::sync::SetOnce;
58
+ /// use tokio::sync::{ SetOnce, SetError} ;
60
59
///
61
60
///
62
61
/// static ONCE: SetOnce<u32> = SetOnce::const_new();
63
62
///
64
63
/// #[tokio::main]
65
- /// async fn main() {
66
- /// let result = ONCE.set(2).await;
67
- /// assert_eq!(*result, 2);
68
- /// }
69
- /// ```
70
- ///
71
- /// It is often useful to write a wrapper method for accessing the value.
72
- ///
73
- /// ```
74
- /// use tokio::sync::SetOnce;
75
- ///
76
- /// static ONCE: SetOnce<u32> = SetOnce::const_new();
77
- ///
78
- /// fn get_global_integer() -> &'static u32 {
79
- /// ONCE.set(2);
80
- /// ONCE.get().unwrap()
81
- /// }
64
+ /// async fn main() -> Result<(), SetError<u32>> {
65
+ /// ONCE.set(2)?;
66
+ /// let result = ONCE.get();
67
+ /// assert_eq!(result, Some(&2));
82
68
///
83
- /// #[tokio::main]
84
- /// async fn main() {
85
- /// let result = get_global_integer();
86
- ///
87
- /// assert_eq!(*result, 2);
69
+ /// Ok(())
88
70
/// }
89
71
/// ```
90
72
pub struct SetOnce < T > {
@@ -124,11 +106,14 @@ impl<T: Eq> Eq for SetOnce<T> {}
124
106
impl < T > Drop for SetOnce < T > {
125
107
fn drop ( & mut self ) {
126
108
if self . initialized ( ) {
109
+ // SAFETY: We're inside the drop implementation of SetOnce
110
+ // AND we're also initalized. This is the best way to ensure
111
+ // out data gets dropped
127
112
unsafe {
128
113
let _ = self . value . with_mut ( |ptr| ptr:: read ( ptr) . assume_init ( ) ) ;
129
114
}
130
-
131
- * self . value_set . get_mut ( ) = false ;
115
+ // no need to set the flag to false as this set once is being
116
+ // dropped
132
117
}
133
118
}
134
119
}
@@ -166,20 +151,21 @@ impl<T> SetOnce<T> {
166
151
/// # Example
167
152
///
168
153
/// ```
169
- /// use tokio::sync::SetOnce;
154
+ /// use tokio::sync::{ SetOnce, SetError} ;
170
155
///
171
156
/// static ONCE: SetOnce<u32> = SetOnce::const_new();
172
157
///
173
- /// fn get_global_integer() -> &'static u32 {
174
- /// ONCE.set(2);
175
- /// ONCE.get().unwrap();
158
+ /// fn get_global_integer() -> Result<Option< &'static u32>, SetError<u32>> {
159
+ /// ONCE.set(2)? ;
160
+ /// Ok( ONCE.get())
176
161
/// }
177
162
///
178
163
/// #[tokio::main]
179
- /// async fn main() {
180
- /// let result = get_global_integer();
164
+ /// async fn main() -> Result<(), SetError<u32>> {
165
+ /// let result = get_global_integer()? ;
181
166
///
182
- /// assert_eq!(*result, 2);
167
+ /// assert_eq!(result, Some(&2));
168
+ /// Ok(())
183
169
/// }
184
170
/// ```
185
171
///
@@ -221,14 +207,15 @@ impl<T> SetOnce<T> {
221
207
///
222
208
/// static ONCE: SetOnce<u32> = SetOnce::const_new_with(1);
223
209
///
224
- /// fn get_global_integer() -> &'static u32 {
225
- /// ONCE.get().unwrap();
210
+ /// fn get_global_integer() -> Option< &'static u32> {
211
+ /// ONCE.get()
226
212
/// }
227
213
///
228
214
/// #[tokio::main]
229
215
/// async fn main() {
230
216
/// let result = get_global_integer();
231
- /// assert_eq!(*result, 1);
217
+ ///
218
+ /// assert_eq!(result, Some(&1));
232
219
/// }
233
220
/// ```
234
221
///
@@ -246,8 +233,8 @@ impl<T> SetOnce<T> {
246
233
/// Returns `true` if the `SetOnce` currently contains a value, and `false`
247
234
/// otherwise.
248
235
pub fn initialized ( & self ) -> bool {
249
- // Using acquire ordering so any threads that read a true from this
250
- // atomic is able to read the value.
236
+ // Using acquire ordering so we're able to read/catch any writes that
237
+ // are done with `Ordering::Release`
251
238
self . value_set . load ( Ordering :: Acquire )
252
239
}
253
240
@@ -315,32 +302,26 @@ impl<T> SetOnce<T> {
315
302
/// Returns `None` if the cell is empty.
316
303
pub fn into_inner ( mut self ) -> Option < T > {
317
304
if self . initialized ( ) {
318
- // SAFETY: The SetOnce is initialized, we can assume the value is
319
- // initialized and return that, when we return the value we give the
320
- // drop handler to someone else and drop is called automatically
321
- //
322
- // We set the value_set as value as we just took the value out
323
- // and the drop implementation will do nothing.
305
+ // Since we have taken ownership of self, its drop implementation
306
+ // will be called by the end of this function, to prevent a double
307
+ // free we will set the value_set to false so that the drop
308
+ // implementation does not try to drop the value again.
324
309
* self . value_set . get_mut ( ) = false ;
310
+
311
+ // SAFETY: The SetOnce is currently initialized, we can assume the
312
+ // value is initialized and return that, when we return the value
313
+ // we give the drop handler to the return scope.
325
314
Some ( unsafe { self . value . with_mut ( |ptr| ptr:: read ( ptr) . assume_init ( ) ) } )
326
315
} else {
327
316
None
328
317
}
329
- // the drop of self is called here again but it doesn't do anything since
330
- // if we dont return early then value is not initalized.
331
- }
332
-
333
- /// Takes ownership of the current value, leaving the cell empty. Returns
334
- /// `None` if the cell is empty.
335
- pub fn take ( & mut self ) -> Option < T > {
336
- std:: mem:: take ( self ) . into_inner ( )
337
318
}
338
319
339
320
/// Waits until the `SetOnce` has been initialized. Once the `SetOnce` is
340
321
/// initialized the wakers are notified and the Future returned from this
341
322
/// function completes.
342
323
///
343
- /// If this function is called after the `SetOnce` is initalized then
324
+ /// If this function is called after the `SetOnce` is initialized then
344
325
/// empty future is returned which completes immediately.
345
326
pub async fn wait ( & self ) {
346
327
if !self . initialized ( ) {
0 commit comments