@@ -9,7 +9,13 @@ use crate::{
9
9
sync:: { Ref , RefBorrow } ,
10
10
} ;
11
11
use alloc:: boxed:: Box ;
12
- use core:: { cell:: UnsafeCell , mem:: MaybeUninit , ops, ops:: Deref , pin:: Pin , ptr:: NonNull } ;
12
+ use core:: {
13
+ cell:: UnsafeCell ,
14
+ mem:: MaybeUninit ,
15
+ ops:: { self , Deref , DerefMut } ,
16
+ pin:: Pin ,
17
+ ptr:: NonNull ,
18
+ } ;
13
19
14
20
/// Permissions.
15
21
///
@@ -200,29 +206,76 @@ impl<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
200
206
/// pr_info!("example2 no early return\n");
201
207
/// }
202
208
/// ```
203
- pub struct ScopeGuard < T : FnOnce ( ) > {
204
- cleanup_func : Option < T > ,
209
+ ///
210
+ /// In the example below, we need a mutable object (the vector) to be accessible within the log
211
+ /// function, so we wrap it in the [`ScopeGuard`]:
212
+ /// ```
213
+ /// # use kernel::prelude::*;
214
+ /// # use kernel::ScopeGuard;
215
+ /// fn example3(arg: bool) -> Result {
216
+ /// let mut vec =
217
+ /// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len()));
218
+ ///
219
+ /// vec.try_push(10u8)?;
220
+ /// if arg {
221
+ /// return Ok(());
222
+ /// }
223
+ /// vec.try_push(20u8)?;
224
+ /// Ok(())
225
+ /// }
226
+ /// ```
227
+ ///
228
+ /// # Invariants
229
+ ///
230
+ /// The value stored in the struct is nearly always `Some(_)`, except between
231
+ /// [`ScopeGuard::dismiss`] and [`ScopeGuard::drop`]: in this case, it will be `None` as the value
232
+ /// will have been returned to the caller. Since [`ScopeGuard::dismiss`] consumes the guard,
233
+ /// callers won't be able to use it anymore.
234
+ pub struct ScopeGuard < T , F : FnOnce ( T ) > ( Option < ( T , F ) > ) ;
235
+
236
+ impl < T , F : FnOnce ( T ) > ScopeGuard < T , F > {
237
+ /// Creates a new guarded object wrapping the given data and with the given cleanup function.
238
+ pub fn new_with_data ( data : T , cleanup_func : F ) -> Self {
239
+ // INVARIANT: The struct is being initialised with `Some(_)`.
240
+ Self ( Some ( ( data, cleanup_func) ) )
241
+ }
242
+
243
+ /// Prevents the cleanup function from running and returns the guarded data.
244
+ pub fn dismiss ( mut self ) -> T {
245
+ // INVARIANT: This is the exception case in the invariant; it is not visible to callers
246
+ // because this function consumes `self`.
247
+ self . 0 . take ( ) . unwrap ( ) . 0
248
+ }
205
249
}
206
250
207
- impl < T : FnOnce ( ) > ScopeGuard < T > {
208
- /// Creates a new cleanup object with the given cleanup function.
209
- pub fn new ( cleanup_func : T ) -> Self {
210
- Self {
211
- cleanup_func : Some ( cleanup_func) ,
212
- }
251
+ impl ScopeGuard < ( ) , Box < dyn FnOnce ( ( ) ) > > {
252
+ /// Creates a new guarded object with the given cleanup function.
253
+ pub fn new ( cleanup : impl FnOnce ( ) ) -> ScopeGuard < ( ) , impl FnOnce ( ( ) ) > {
254
+ ScopeGuard :: new_with_data ( ( ) , move |_| cleanup ( ) )
213
255
}
256
+ }
257
+
258
+ impl < T , F : FnOnce ( T ) > Deref for ScopeGuard < T , F > {
259
+ type Target = T ;
260
+
261
+ fn deref ( & self ) -> & T {
262
+ // The type invariants guarantee that `unwrap` will succeed.
263
+ & self . 0 . as_ref ( ) . unwrap ( ) . 0
264
+ }
265
+ }
214
266
215
- /// Prevents the cleanup function from running.
216
- pub fn dismiss ( mut self ) {
217
- self . cleanup_func . take ( ) ;
267
+ impl < T , F : FnOnce ( T ) > DerefMut for ScopeGuard < T , F > {
268
+ fn deref_mut ( & mut self ) -> & mut T {
269
+ // The type invariants guarantee that `unwrap` will succeed.
270
+ & mut self . 0 . as_mut ( ) . unwrap ( ) . 0
218
271
}
219
272
}
220
273
221
- impl < T : FnOnce ( ) > Drop for ScopeGuard < T > {
274
+ impl < T , F : FnOnce ( T ) > Drop for ScopeGuard < T , F > {
222
275
fn drop ( & mut self ) {
223
276
// Run the cleanup function if one is still present.
224
- if let Some ( cleanup) = self . cleanup_func . take ( ) {
225
- cleanup ( ) ;
277
+ if let Some ( ( data , cleanup) ) = self . 0 . take ( ) {
278
+ cleanup ( data )
226
279
}
227
280
}
228
281
}
0 commit comments