1 | #![cfg_attr (not(any(test, feature = "use_std" )), no_std)] |
2 | #![doc (html_root_url = "https://docs.rs/scopeguard/1/" )] |
3 | |
4 | //! A scope guard will run a given closure when it goes out of scope, |
5 | //! even if the code between panics. |
6 | //! (as long as panic doesn't abort) |
7 | //! |
8 | //! # Examples |
9 | //! |
10 | //! ## Hello World |
11 | //! |
12 | //! This example creates a scope guard with an example function: |
13 | //! |
14 | //! ``` |
15 | //! extern crate scopeguard; |
16 | //! |
17 | //! fn f() { |
18 | //! let _guard = scopeguard::guard((), |_| { |
19 | //! println!("Hello Scope Exit!" ); |
20 | //! }); |
21 | //! |
22 | //! // rest of the code here. |
23 | //! |
24 | //! // Here, at the end of `_guard`'s scope, the guard's closure is called. |
25 | //! // It is also called if we exit this scope through unwinding instead. |
26 | //! } |
27 | //! # fn main() { |
28 | //! # f(); |
29 | //! # } |
30 | //! ``` |
31 | //! |
32 | //! ## `defer!` |
33 | //! |
34 | //! Use the `defer` macro to run an operation at scope exit, |
35 | //! either regular scope exit or during unwinding from a panic. |
36 | //! |
37 | //! ``` |
38 | //! #[macro_use(defer)] extern crate scopeguard; |
39 | //! |
40 | //! use std::cell::Cell; |
41 | //! |
42 | //! fn main() { |
43 | //! // use a cell to observe drops during and after the scope guard is active |
44 | //! let drop_counter = Cell::new(0); |
45 | //! { |
46 | //! // Create a scope guard using `defer!` for the current scope |
47 | //! defer! { |
48 | //! drop_counter.set(1 + drop_counter.get()); |
49 | //! } |
50 | //! |
51 | //! // Do regular operations here in the meantime. |
52 | //! |
53 | //! // Just before scope exit: it hasn't run yet. |
54 | //! assert_eq!(drop_counter.get(), 0); |
55 | //! |
56 | //! // The following scope end is where the defer closure is called |
57 | //! } |
58 | //! assert_eq!(drop_counter.get(), 1); |
59 | //! } |
60 | //! ``` |
61 | //! |
62 | //! ## Scope Guard with Value |
63 | //! |
64 | //! If the scope guard closure needs to access an outer value that is also |
65 | //! mutated outside of the scope guard, then you may want to use the scope guard |
66 | //! with a value. The guard works like a smart pointer, so the inner value can |
67 | //! be accessed by reference or by mutable reference. |
68 | //! |
69 | //! ### 1. The guard owns a file |
70 | //! |
71 | //! In this example, the scope guard owns a file and ensures pending writes are |
72 | //! synced at scope exit. |
73 | //! |
74 | //! ``` |
75 | //! extern crate scopeguard; |
76 | //! |
77 | //! use std::fs::*; |
78 | //! use std::io::{self, Write}; |
79 | //! # // Mock file so that we don't actually write a file |
80 | //! # struct MockFile; |
81 | //! # impl MockFile { |
82 | //! # fn create(_s: &str) -> io::Result<Self> { Ok(MockFile) } |
83 | //! # fn write_all(&self, _b: &[u8]) -> io::Result<()> { Ok(()) } |
84 | //! # fn sync_all(&self) -> io::Result<()> { Ok(()) } |
85 | //! # } |
86 | //! # use self::MockFile as File; |
87 | //! |
88 | //! fn try_main() -> io::Result<()> { |
89 | //! let f = File::create("newfile.txt" )?; |
90 | //! let mut file = scopeguard::guard(f, |f| { |
91 | //! // ensure we flush file at return or panic |
92 | //! let _ = f.sync_all(); |
93 | //! }); |
94 | //! // Access the file through the scope guard itself |
95 | //! file.write_all(b"test me \n" ).map(|_| ()) |
96 | //! } |
97 | //! |
98 | //! fn main() { |
99 | //! try_main().unwrap(); |
100 | //! } |
101 | //! |
102 | //! ``` |
103 | //! |
104 | //! ### 2. The guard restores an invariant on scope exit |
105 | //! |
106 | //! ``` |
107 | //! extern crate scopeguard; |
108 | //! |
109 | //! use std::mem::ManuallyDrop; |
110 | //! use std::ptr; |
111 | //! |
112 | //! // This function, just for this example, takes the first element |
113 | //! // and inserts it into the assumed sorted tail of the vector. |
114 | //! // |
115 | //! // For optimization purposes we temporarily violate an invariant of the |
116 | //! // Vec, that it owns all of its elements. |
117 | //! // |
118 | //! // The safe approach is to use swap, which means two writes to memory, |
119 | //! // the optimization is to use a “hole” which uses only one write of memory |
120 | //! // for each position it moves. |
121 | //! // |
122 | //! // We *must* use a scope guard to run this code safely. We |
123 | //! // are running arbitrary user code (comparison operators) that may panic. |
124 | //! // The scope guard ensures we restore the invariant after successful |
125 | //! // exit or during unwinding from panic. |
126 | //! fn insertion_sort_first<T>(v: &mut Vec<T>) |
127 | //! where T: PartialOrd |
128 | //! { |
129 | //! struct Hole<'a, T: 'a> { |
130 | //! v: &'a mut Vec<T>, |
131 | //! index: usize, |
132 | //! value: ManuallyDrop<T>, |
133 | //! } |
134 | //! |
135 | //! unsafe { |
136 | //! // Create a moved-from location in the vector, a “hole”. |
137 | //! let value = ptr::read(&v[0]); |
138 | //! let mut hole = Hole { v: v, index: 0, value: ManuallyDrop::new(value) }; |
139 | //! |
140 | //! // Use a scope guard with a value. |
141 | //! // At scope exit, plug the hole so that the vector is fully |
142 | //! // initialized again. |
143 | //! // The scope guard owns the hole, but we can access it through the guard. |
144 | //! let mut hole_guard = scopeguard::guard(hole, |hole| { |
145 | //! // plug the hole in the vector with the value that was // taken out |
146 | //! let index = hole.index; |
147 | //! ptr::copy_nonoverlapping(&*hole.value, &mut hole.v[index], 1); |
148 | //! }); |
149 | //! |
150 | //! // run algorithm that moves the hole in the vector here |
151 | //! // move the hole until it's in a sorted position |
152 | //! for i in 1..hole_guard.v.len() { |
153 | //! if *hole_guard.value >= hole_guard.v[i] { |
154 | //! // move the element back and the hole forward |
155 | //! let index = hole_guard.index; |
156 | //! ptr::copy_nonoverlapping(&hole_guard.v[index + 1], &mut hole_guard.v[index], 1); |
157 | //! hole_guard.index += 1; |
158 | //! } else { |
159 | //! break; |
160 | //! } |
161 | //! } |
162 | //! |
163 | //! // When the scope exits here, the Vec becomes whole again! |
164 | //! } |
165 | //! } |
166 | //! |
167 | //! fn main() { |
168 | //! let string = String::from; |
169 | //! let mut data = vec![string("c" ), string("a" ), string("b" ), string("d" )]; |
170 | //! insertion_sort_first(&mut data); |
171 | //! assert_eq!(data, vec!["a" , "b" , "c" , "d" ]); |
172 | //! } |
173 | //! |
174 | //! ``` |
175 | //! |
176 | //! |
177 | //! # Crate Features |
178 | //! |
179 | //! - `use_std` |
180 | //! + Enabled by default. Enables the `OnUnwind` and `OnSuccess` strategies. |
181 | //! + Disable to use `no_std`. |
182 | //! |
183 | //! # Rust Version |
184 | //! |
185 | //! This version of the crate requires Rust 1.20 or later. |
186 | //! |
187 | //! The scopeguard 1.x release series will use a carefully considered version |
188 | //! upgrade policy, where in a later 1.x version, we will raise the minimum |
189 | //! required Rust version. |
190 | |
191 | #[cfg (not(any(test, feature = "use_std" )))] |
192 | extern crate core as std; |
193 | |
194 | use std::fmt; |
195 | use std::marker::PhantomData; |
196 | use std::mem::{self, ManuallyDrop}; |
197 | use std::ops::{Deref, DerefMut}; |
198 | use std::ptr; |
199 | |
200 | /// Controls in which cases the associated code should be run |
201 | pub trait Strategy { |
202 | /// Return `true` if the guard’s associated code should run |
203 | /// (in the context where this method is called). |
204 | fn should_run() -> bool; |
205 | } |
206 | |
207 | /// Always run on scope exit. |
208 | /// |
209 | /// “Always” run: on regular exit from a scope or on unwinding from a panic. |
210 | /// Can not run on abort, process exit, and other catastrophic events where |
211 | /// destructors don’t run. |
212 | #[derive (Debug)] |
213 | pub enum Always {} |
214 | |
215 | /// Run on scope exit through unwinding. |
216 | /// |
217 | /// Requires crate feature `use_std`. |
218 | #[cfg (feature = "use_std" )] |
219 | #[derive (Debug)] |
220 | pub enum OnUnwind {} |
221 | |
222 | /// Run on regular scope exit, when not unwinding. |
223 | /// |
224 | /// Requires crate feature `use_std`. |
225 | #[cfg (feature = "use_std" )] |
226 | #[derive (Debug)] |
227 | pub enum OnSuccess {} |
228 | |
229 | impl Strategy for Always { |
230 | #[inline (always)] |
231 | fn should_run() -> bool { true } |
232 | } |
233 | |
234 | #[cfg (feature = "use_std" )] |
235 | impl Strategy for OnUnwind { |
236 | #[inline ] |
237 | fn should_run() -> bool { std::thread::panicking() } |
238 | } |
239 | |
240 | #[cfg (feature = "use_std" )] |
241 | impl Strategy for OnSuccess { |
242 | #[inline ] |
243 | fn should_run() -> bool { !std::thread::panicking() } |
244 | } |
245 | |
246 | /// Macro to create a `ScopeGuard` (always run). |
247 | /// |
248 | /// The macro takes statements, which are the body of a closure |
249 | /// that will run when the scope is exited. |
250 | #[macro_export ] |
251 | macro_rules! defer { |
252 | ($($t:tt)*) => { |
253 | let _guard = $crate::guard((), |()| { $($t)* }); |
254 | }; |
255 | } |
256 | |
257 | /// Macro to create a `ScopeGuard` (run on successful scope exit). |
258 | /// |
259 | /// The macro takes statements, which are the body of a closure |
260 | /// that will run when the scope is exited. |
261 | /// |
262 | /// Requires crate feature `use_std`. |
263 | #[cfg (feature = "use_std" )] |
264 | #[macro_export ] |
265 | macro_rules! defer_on_success { |
266 | ($($t:tt)*) => { |
267 | let _guard = $crate::guard_on_success((), |()| { $($t)* }); |
268 | }; |
269 | } |
270 | |
271 | /// Macro to create a `ScopeGuard` (run on unwinding from panic). |
272 | /// |
273 | /// The macro takes statements, which are the body of a closure |
274 | /// that will run when the scope is exited. |
275 | /// |
276 | /// Requires crate feature `use_std`. |
277 | #[cfg (feature = "use_std" )] |
278 | #[macro_export ] |
279 | macro_rules! defer_on_unwind { |
280 | ($($t:tt)*) => { |
281 | let _guard = $crate::guard_on_unwind((), |()| { $($t)* }); |
282 | }; |
283 | } |
284 | |
285 | /// `ScopeGuard` is a scope guard that may own a protected value. |
286 | /// |
287 | /// If you place a guard in a local variable, the closure can |
288 | /// run regardless how you leave the scope — through regular return or panic |
289 | /// (except if panic or other code aborts; so as long as destructors run). |
290 | /// It is run only once. |
291 | /// |
292 | /// The `S` parameter for [`Strategy`](trait.Strategy.html) determines if |
293 | /// the closure actually runs. |
294 | /// |
295 | /// The guard's closure will be called with the held value in the destructor. |
296 | /// |
297 | /// The `ScopeGuard` implements `Deref` so that you can access the inner value. |
298 | pub struct ScopeGuard<T, F, S = Always> |
299 | where F: FnOnce(T), |
300 | S: Strategy, |
301 | { |
302 | value: ManuallyDrop<T>, |
303 | dropfn: ManuallyDrop<F>, |
304 | // fn(S) -> S is used, so that the S is not taken into account for auto traits. |
305 | strategy: PhantomData<fn(S) -> S>, |
306 | } |
307 | |
308 | impl<T, F, S> ScopeGuard<T, F, S> |
309 | where F: FnOnce(T), |
310 | S: Strategy, |
311 | { |
312 | /// Create a `ScopeGuard` that owns `v` (accessible through deref) and calls |
313 | /// `dropfn` when its destructor runs. |
314 | /// |
315 | /// The `Strategy` decides whether the scope guard's closure should run. |
316 | #[inline ] |
317 | pub fn with_strategy(v: T, dropfn: F) -> ScopeGuard<T, F, S> { |
318 | ScopeGuard { |
319 | value: ManuallyDrop::new(v), |
320 | dropfn: ManuallyDrop::new(dropfn), |
321 | strategy: PhantomData, |
322 | } |
323 | } |
324 | |
325 | /// “Defuse” the guard and extract the value without calling the closure. |
326 | /// |
327 | /// ``` |
328 | /// extern crate scopeguard; |
329 | /// |
330 | /// use scopeguard::{guard, ScopeGuard}; |
331 | /// |
332 | /// fn conditional() -> bool { true } |
333 | /// |
334 | /// fn main() { |
335 | /// let mut guard = guard(Vec::new(), |mut v| v.clear()); |
336 | /// guard.push(1); |
337 | /// |
338 | /// if conditional() { |
339 | /// // a condition maybe makes us decide to |
340 | /// // “defuse” the guard and get back its inner parts |
341 | /// let value = ScopeGuard::into_inner(guard); |
342 | /// } else { |
343 | /// // guard still exists in this branch |
344 | /// } |
345 | /// } |
346 | /// ``` |
347 | #[inline ] |
348 | pub fn into_inner(guard: Self) -> T { |
349 | // Cannot move out of Drop-implementing types, so |
350 | // ptr::read the value and forget the guard. |
351 | unsafe { |
352 | let value = ptr::read(&*guard.value); |
353 | // read the closure so that it is dropped, and assign it to a local |
354 | // variable to ensure that it is only dropped after the guard has |
355 | // been forgotten. (In case the Drop impl of the closure, or that |
356 | // of any consumed captured variable, panics). |
357 | let _dropfn = ptr::read(&*guard.dropfn); |
358 | mem::forget(guard); |
359 | value |
360 | } |
361 | } |
362 | } |
363 | |
364 | |
365 | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
366 | #[inline ] |
367 | pub fn guard<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, Always> |
368 | where F: FnOnce(T) |
369 | { |
370 | ScopeGuard::with_strategy(v, dropfn) |
371 | } |
372 | |
373 | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
374 | /// |
375 | /// Requires crate feature `use_std`. |
376 | #[cfg (feature = "use_std" )] |
377 | #[inline ] |
378 | pub fn guard_on_success<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnSuccess> |
379 | where F: FnOnce(T) |
380 | { |
381 | ScopeGuard::with_strategy(v, dropfn) |
382 | } |
383 | |
384 | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
385 | /// |
386 | /// Requires crate feature `use_std`. |
387 | /// |
388 | /// ## Examples |
389 | /// |
390 | /// For performance reasons, or to emulate “only run guard on unwind” in |
391 | /// no-std environments, we can also use the default guard and simply manually |
392 | /// defuse it at the end of scope like the following example. (The performance |
393 | /// reason would be if the [`OnUnwind`]'s call to [std::thread::panicking()] is |
394 | /// an issue.) |
395 | /// |
396 | /// ``` |
397 | /// extern crate scopeguard; |
398 | /// |
399 | /// use scopeguard::ScopeGuard; |
400 | /// # fn main() { |
401 | /// { |
402 | /// let guard = scopeguard::guard((), |_| {}); |
403 | /// |
404 | /// // rest of the code here |
405 | /// |
406 | /// // we reached the end of scope without unwinding - defuse it |
407 | /// ScopeGuard::into_inner(guard); |
408 | /// } |
409 | /// # } |
410 | /// ``` |
411 | #[cfg (feature = "use_std" )] |
412 | #[inline ] |
413 | pub fn guard_on_unwind<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnUnwind> |
414 | where F: FnOnce(T) |
415 | { |
416 | ScopeGuard::with_strategy(v, dropfn) |
417 | } |
418 | |
419 | // ScopeGuard can be Sync even if F isn't because the closure is |
420 | // not accessible from references. |
421 | // The guard does not store any instance of S, so it is also irrelevant. |
422 | unsafe impl<T, F, S> Sync for ScopeGuard<T, F, S> |
423 | where T: Sync, |
424 | F: FnOnce(T), |
425 | S: Strategy |
426 | {} |
427 | |
428 | impl<T, F, S> Deref for ScopeGuard<T, F, S> |
429 | where F: FnOnce(T), |
430 | S: Strategy |
431 | { |
432 | type Target = T; |
433 | |
434 | fn deref(&self) -> &T { |
435 | &*self.value |
436 | } |
437 | } |
438 | |
439 | impl<T, F, S> DerefMut for ScopeGuard<T, F, S> |
440 | where F: FnOnce(T), |
441 | S: Strategy |
442 | { |
443 | fn deref_mut(&mut self) -> &mut T { |
444 | &mut *self.value |
445 | } |
446 | } |
447 | |
448 | impl<T, F, S> Drop for ScopeGuard<T, F, S> |
449 | where F: FnOnce(T), |
450 | S: Strategy |
451 | { |
452 | fn drop(&mut self) { |
453 | // This is OK because the fields are `ManuallyDrop`s |
454 | // which will not be dropped by the compiler. |
455 | let (value: T, dropfn: F) = unsafe { |
456 | (ptr::read(&*self.value), ptr::read(&*self.dropfn)) |
457 | }; |
458 | if S::should_run() { |
459 | dropfn(value); |
460 | } |
461 | } |
462 | } |
463 | |
464 | impl<T, F, S> fmt::Debug for ScopeGuard<T, F, S> |
465 | where T: fmt::Debug, |
466 | F: FnOnce(T), |
467 | S: Strategy |
468 | { |
469 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
470 | f&mut DebugStruct<'_, '_>.debug_struct(stringify!(ScopeGuard)) |
471 | .field(name:"value" , &*self.value) |
472 | .finish() |
473 | } |
474 | } |
475 | |
476 | #[cfg (test)] |
477 | mod tests { |
478 | use super::*; |
479 | use std::cell::Cell; |
480 | use std::panic::catch_unwind; |
481 | use std::panic::AssertUnwindSafe; |
482 | |
483 | #[test ] |
484 | fn test_defer() { |
485 | let drops = Cell::new(0); |
486 | defer!(drops.set(1000)); |
487 | assert_eq!(drops.get(), 0); |
488 | } |
489 | |
490 | #[cfg (feature = "use_std" )] |
491 | #[test ] |
492 | fn test_defer_success_1() { |
493 | let drops = Cell::new(0); |
494 | { |
495 | defer_on_success!(drops.set(1)); |
496 | assert_eq!(drops.get(), 0); |
497 | } |
498 | assert_eq!(drops.get(), 1); |
499 | } |
500 | |
501 | #[cfg (feature = "use_std" )] |
502 | #[test ] |
503 | fn test_defer_success_2() { |
504 | let drops = Cell::new(0); |
505 | let _ = catch_unwind(AssertUnwindSafe(|| { |
506 | defer_on_success!(drops.set(1)); |
507 | panic!("failure" ) |
508 | })); |
509 | assert_eq!(drops.get(), 0); |
510 | } |
511 | |
512 | #[cfg (feature = "use_std" )] |
513 | #[test ] |
514 | fn test_defer_unwind_1() { |
515 | let drops = Cell::new(0); |
516 | let _ = catch_unwind(AssertUnwindSafe(|| { |
517 | defer_on_unwind!(drops.set(1)); |
518 | assert_eq!(drops.get(), 0); |
519 | panic!("failure" ) |
520 | })); |
521 | assert_eq!(drops.get(), 1); |
522 | } |
523 | |
524 | #[cfg (feature = "use_std" )] |
525 | #[test ] |
526 | fn test_defer_unwind_2() { |
527 | let drops = Cell::new(0); |
528 | { |
529 | defer_on_unwind!(drops.set(1)); |
530 | } |
531 | assert_eq!(drops.get(), 0); |
532 | } |
533 | |
534 | #[test ] |
535 | fn test_only_dropped_by_closure_when_run() { |
536 | let value_drops = Cell::new(0); |
537 | let value = guard((), |()| value_drops.set(1 + value_drops.get())); |
538 | let closure_drops = Cell::new(0); |
539 | let guard = guard(value, |_| closure_drops.set(1 + closure_drops.get())); |
540 | assert_eq!(value_drops.get(), 0); |
541 | assert_eq!(closure_drops.get(), 0); |
542 | drop(guard); |
543 | assert_eq!(value_drops.get(), 1); |
544 | assert_eq!(closure_drops.get(), 1); |
545 | } |
546 | |
547 | #[cfg (feature = "use_std" )] |
548 | #[test ] |
549 | fn test_dropped_once_when_not_run() { |
550 | let value_drops = Cell::new(0); |
551 | let value = guard((), |()| value_drops.set(1 + value_drops.get())); |
552 | let captured_drops = Cell::new(0); |
553 | let captured = guard((), |()| captured_drops.set(1 + captured_drops.get())); |
554 | let closure_drops = Cell::new(0); |
555 | let guard = guard_on_unwind(value, |value| { |
556 | drop(value); |
557 | drop(captured); |
558 | closure_drops.set(1 + closure_drops.get()) |
559 | }); |
560 | assert_eq!(value_drops.get(), 0); |
561 | assert_eq!(captured_drops.get(), 0); |
562 | assert_eq!(closure_drops.get(), 0); |
563 | drop(guard); |
564 | assert_eq!(value_drops.get(), 1); |
565 | assert_eq!(captured_drops.get(), 1); |
566 | assert_eq!(closure_drops.get(), 0); |
567 | } |
568 | |
569 | #[test ] |
570 | fn test_into_inner() { |
571 | let dropped = Cell::new(false); |
572 | let value = guard(42, |_| dropped.set(true)); |
573 | let guard = guard(value, |_| dropped.set(true)); |
574 | let inner = ScopeGuard::into_inner(guard); |
575 | assert_eq!(dropped.get(), false); |
576 | assert_eq!(*inner, 42); |
577 | } |
578 | } |
579 | |