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 | //! hole_guard.v.swap(index, 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::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 { |
232 | true |
233 | } |
234 | } |
235 | |
236 | #[cfg (feature = "use_std" )] |
237 | impl Strategy for OnUnwind { |
238 | #[inline ] |
239 | fn should_run() -> bool { |
240 | std::thread::panicking() |
241 | } |
242 | } |
243 | |
244 | #[cfg (feature = "use_std" )] |
245 | impl Strategy for OnSuccess { |
246 | #[inline ] |
247 | fn should_run() -> bool { |
248 | !std::thread::panicking() |
249 | } |
250 | } |
251 | |
252 | /// Macro to create a `ScopeGuard` (always run). |
253 | /// |
254 | /// The macro takes statements, which are the body of a closure |
255 | /// that will run when the scope is exited. |
256 | #[macro_export ] |
257 | macro_rules! defer { |
258 | ($($t:tt)*) => { |
259 | let _guard = $crate::guard((), |()| { $($t)* }); |
260 | }; |
261 | } |
262 | |
263 | /// Macro to create a `ScopeGuard` (run on successful scope exit). |
264 | /// |
265 | /// The macro takes statements, which are the body of a closure |
266 | /// that will run when the scope is exited. |
267 | /// |
268 | /// Requires crate feature `use_std`. |
269 | #[cfg (feature = "use_std" )] |
270 | #[macro_export ] |
271 | macro_rules! defer_on_success { |
272 | ($($t:tt)*) => { |
273 | let _guard = $crate::guard_on_success((), |()| { $($t)* }); |
274 | }; |
275 | } |
276 | |
277 | /// Macro to create a `ScopeGuard` (run on unwinding from panic). |
278 | /// |
279 | /// The macro takes statements, which are the body of a closure |
280 | /// that will run when the scope is exited. |
281 | /// |
282 | /// Requires crate feature `use_std`. |
283 | #[cfg (feature = "use_std" )] |
284 | #[macro_export ] |
285 | macro_rules! defer_on_unwind { |
286 | ($($t:tt)*) => { |
287 | let _guard = $crate::guard_on_unwind((), |()| { $($t)* }); |
288 | }; |
289 | } |
290 | |
291 | /// `ScopeGuard` is a scope guard that may own a protected value. |
292 | /// |
293 | /// If you place a guard in a local variable, the closure can |
294 | /// run regardless how you leave the scope — through regular return or panic |
295 | /// (except if panic or other code aborts; so as long as destructors run). |
296 | /// It is run only once. |
297 | /// |
298 | /// The `S` parameter for [`Strategy`](trait.Strategy.html) determines if |
299 | /// the closure actually runs. |
300 | /// |
301 | /// The guard's closure will be called with the held value in the destructor. |
302 | /// |
303 | /// The `ScopeGuard` implements `Deref` so that you can access the inner value. |
304 | pub struct ScopeGuard<T, F, S = Always> |
305 | where |
306 | F: FnOnce(T), |
307 | S: Strategy, |
308 | { |
309 | value: ManuallyDrop<T>, |
310 | dropfn: ManuallyDrop<F>, |
311 | // fn(S) -> S is used, so that the S is not taken into account for auto traits. |
312 | strategy: PhantomData<fn(S) -> S>, |
313 | } |
314 | |
315 | impl<T, F, S> ScopeGuard<T, F, S> |
316 | where |
317 | F: FnOnce(T), |
318 | S: Strategy, |
319 | { |
320 | /// Create a `ScopeGuard` that owns `v` (accessible through deref) and calls |
321 | /// `dropfn` when its destructor runs. |
322 | /// |
323 | /// The `Strategy` decides whether the scope guard's closure should run. |
324 | #[inline ] |
325 | #[must_use ] |
326 | pub fn with_strategy(v: T, dropfn: F) -> ScopeGuard<T, F, S> { |
327 | ScopeGuard { |
328 | value: ManuallyDrop::new(v), |
329 | dropfn: ManuallyDrop::new(dropfn), |
330 | strategy: PhantomData, |
331 | } |
332 | } |
333 | |
334 | /// “Defuse” the guard and extract the value without calling the closure. |
335 | /// |
336 | /// ``` |
337 | /// extern crate scopeguard; |
338 | /// |
339 | /// use scopeguard::{guard, ScopeGuard}; |
340 | /// |
341 | /// fn conditional() -> bool { true } |
342 | /// |
343 | /// fn main() { |
344 | /// let mut guard = guard(Vec::new(), |mut v| v.clear()); |
345 | /// guard.push(1); |
346 | /// |
347 | /// if conditional() { |
348 | /// // a condition maybe makes us decide to |
349 | /// // “defuse” the guard and get back its inner parts |
350 | /// let value = ScopeGuard::into_inner(guard); |
351 | /// } else { |
352 | /// // guard still exists in this branch |
353 | /// } |
354 | /// } |
355 | /// ``` |
356 | #[inline ] |
357 | pub fn into_inner(guard: Self) -> T { |
358 | // Cannot move out of `Drop`-implementing types, |
359 | // so `ptr::read` the value and forget the guard. |
360 | let mut guard = ManuallyDrop::new(guard); |
361 | unsafe { |
362 | let value = ptr::read(&*guard.value); |
363 | // Drop the closure after `value` has been read, so that if the |
364 | // closure's `drop` function panics, unwinding still tries to drop |
365 | // `value`. |
366 | ManuallyDrop::drop(&mut guard.dropfn); |
367 | value |
368 | } |
369 | } |
370 | } |
371 | |
372 | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
373 | #[inline ] |
374 | #[must_use ] |
375 | pub fn guard<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, Always> |
376 | where |
377 | F: FnOnce(T), |
378 | { |
379 | ScopeGuard::with_strategy(v, dropfn) |
380 | } |
381 | |
382 | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
383 | /// |
384 | /// Requires crate feature `use_std`. |
385 | #[cfg (feature = "use_std" )] |
386 | #[inline ] |
387 | #[must_use ] |
388 | pub fn guard_on_success<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnSuccess> |
389 | where |
390 | F: FnOnce(T), |
391 | { |
392 | ScopeGuard::with_strategy(v, dropfn) |
393 | } |
394 | |
395 | /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. |
396 | /// |
397 | /// Requires crate feature `use_std`. |
398 | /// |
399 | /// ## Examples |
400 | /// |
401 | /// For performance reasons, or to emulate “only run guard on unwind” in |
402 | /// no-std environments, we can also use the default guard and simply manually |
403 | /// defuse it at the end of scope like the following example. (The performance |
404 | /// reason would be if the [`OnUnwind`]'s call to [std::thread::panicking()] is |
405 | /// an issue.) |
406 | /// |
407 | /// ``` |
408 | /// extern crate scopeguard; |
409 | /// |
410 | /// use scopeguard::ScopeGuard; |
411 | /// # fn main() { |
412 | /// { |
413 | /// let guard = scopeguard::guard((), |_| {}); |
414 | /// |
415 | /// // rest of the code here |
416 | /// |
417 | /// // we reached the end of scope without unwinding - defuse it |
418 | /// ScopeGuard::into_inner(guard); |
419 | /// } |
420 | /// # } |
421 | /// ``` |
422 | #[cfg (feature = "use_std" )] |
423 | #[inline ] |
424 | #[must_use ] |
425 | pub fn guard_on_unwind<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnUnwind> |
426 | where |
427 | F: FnOnce(T), |
428 | { |
429 | ScopeGuard::with_strategy(v, dropfn) |
430 | } |
431 | |
432 | // ScopeGuard can be Sync even if F isn't because the closure is |
433 | // not accessible from references. |
434 | // The guard does not store any instance of S, so it is also irrelevant. |
435 | unsafe impl<T, F, S> Sync for ScopeGuard<T, F, S> |
436 | where |
437 | T: Sync, |
438 | F: FnOnce(T), |
439 | S: Strategy, |
440 | { |
441 | } |
442 | |
443 | impl<T, F, S> Deref for ScopeGuard<T, F, S> |
444 | where |
445 | F: FnOnce(T), |
446 | S: Strategy, |
447 | { |
448 | type Target = T; |
449 | |
450 | fn deref(&self) -> &T { |
451 | &*self.value |
452 | } |
453 | } |
454 | |
455 | impl<T, F, S> DerefMut for ScopeGuard<T, F, S> |
456 | where |
457 | F: FnOnce(T), |
458 | S: Strategy, |
459 | { |
460 | fn deref_mut(&mut self) -> &mut T { |
461 | &mut *self.value |
462 | } |
463 | } |
464 | |
465 | impl<T, F, S> Drop for ScopeGuard<T, F, S> |
466 | where |
467 | F: FnOnce(T), |
468 | S: Strategy, |
469 | { |
470 | fn drop(&mut self) { |
471 | // This is OK because the fields are `ManuallyDrop`s |
472 | // which will not be dropped by the compiler. |
473 | let (value, dropfn) = unsafe { (ptr::read(&*self.value), ptr::read(&*self.dropfn)) }; |
474 | if S::should_run() { |
475 | dropfn(value); |
476 | } |
477 | } |
478 | } |
479 | |
480 | impl<T, F, S> fmt::Debug for ScopeGuard<T, F, S> |
481 | where |
482 | T: fmt::Debug, |
483 | F: FnOnce(T), |
484 | S: Strategy, |
485 | { |
486 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
487 | f.debug_struct(stringify!(ScopeGuard)) |
488 | .field("value" , &*self.value) |
489 | .finish() |
490 | } |
491 | } |
492 | |
493 | #[cfg (test)] |
494 | mod tests { |
495 | use super::*; |
496 | use std::cell::Cell; |
497 | use std::panic::catch_unwind; |
498 | use std::panic::AssertUnwindSafe; |
499 | |
500 | #[test] |
501 | fn test_defer() { |
502 | let drops = Cell::new(0); |
503 | defer!(drops.set(1000)); |
504 | assert_eq!(drops.get(), 0); |
505 | } |
506 | |
507 | #[cfg (feature = "use_std" )] |
508 | #[test] |
509 | fn test_defer_success_1() { |
510 | let drops = Cell::new(0); |
511 | { |
512 | defer_on_success!(drops.set(1)); |
513 | assert_eq!(drops.get(), 0); |
514 | } |
515 | assert_eq!(drops.get(), 1); |
516 | } |
517 | |
518 | #[cfg (feature = "use_std" )] |
519 | #[test] |
520 | fn test_defer_success_2() { |
521 | let drops = Cell::new(0); |
522 | let _ = catch_unwind(AssertUnwindSafe(|| { |
523 | defer_on_success!(drops.set(1)); |
524 | panic!("failure" ) |
525 | })); |
526 | assert_eq!(drops.get(), 0); |
527 | } |
528 | |
529 | #[cfg (feature = "use_std" )] |
530 | #[test] |
531 | fn test_defer_unwind_1() { |
532 | let drops = Cell::new(0); |
533 | let _ = catch_unwind(AssertUnwindSafe(|| { |
534 | defer_on_unwind!(drops.set(1)); |
535 | assert_eq!(drops.get(), 0); |
536 | panic!("failure" ) |
537 | })); |
538 | assert_eq!(drops.get(), 1); |
539 | } |
540 | |
541 | #[cfg (feature = "use_std" )] |
542 | #[test] |
543 | fn test_defer_unwind_2() { |
544 | let drops = Cell::new(0); |
545 | { |
546 | defer_on_unwind!(drops.set(1)); |
547 | } |
548 | assert_eq!(drops.get(), 0); |
549 | } |
550 | |
551 | #[test] |
552 | fn test_only_dropped_by_closure_when_run() { |
553 | let value_drops = Cell::new(0); |
554 | let value = guard((), |()| value_drops.set(1 + value_drops.get())); |
555 | let closure_drops = Cell::new(0); |
556 | let guard = guard(value, |_| closure_drops.set(1 + closure_drops.get())); |
557 | assert_eq!(value_drops.get(), 0); |
558 | assert_eq!(closure_drops.get(), 0); |
559 | drop(guard); |
560 | assert_eq!(value_drops.get(), 1); |
561 | assert_eq!(closure_drops.get(), 1); |
562 | } |
563 | |
564 | #[cfg (feature = "use_std" )] |
565 | #[test] |
566 | fn test_dropped_once_when_not_run() { |
567 | let value_drops = Cell::new(0); |
568 | let value = guard((), |()| value_drops.set(1 + value_drops.get())); |
569 | let captured_drops = Cell::new(0); |
570 | let captured = guard((), |()| captured_drops.set(1 + captured_drops.get())); |
571 | let closure_drops = Cell::new(0); |
572 | let guard = guard_on_unwind(value, |value| { |
573 | drop(value); |
574 | drop(captured); |
575 | closure_drops.set(1 + closure_drops.get()) |
576 | }); |
577 | assert_eq!(value_drops.get(), 0); |
578 | assert_eq!(captured_drops.get(), 0); |
579 | assert_eq!(closure_drops.get(), 0); |
580 | drop(guard); |
581 | assert_eq!(value_drops.get(), 1); |
582 | assert_eq!(captured_drops.get(), 1); |
583 | assert_eq!(closure_drops.get(), 0); |
584 | } |
585 | |
586 | #[test] |
587 | fn test_into_inner() { |
588 | let dropped = Cell::new(false); |
589 | let value = guard(42, |_| dropped.set(true)); |
590 | let guard = guard(value, |_| dropped.set(true)); |
591 | let inner = ScopeGuard::into_inner(guard); |
592 | assert_eq!(dropped.get(), false); |
593 | assert_eq!(*inner, 42); |
594 | } |
595 | } |
596 | |