#![cfg_attr(not(any(test, feature = "use_std")), no_std)] #![doc(html_root_url = "https://docs.rs/scopeguard/1/")] //! A scope guard will run a given closure when it goes out of scope, //! even if the code between panics. //! (as long as panic doesn't abort) //! //! # Examples //! //! ## Hello World //! //! This example creates a scope guard with an example function: //! //! ``` //! extern crate scopeguard; //! //! fn f() { //! let _guard = scopeguard::guard((), |_| { //! println!("Hello Scope Exit!"); //! }); //! //! // rest of the code here. //! //! // Here, at the end of `_guard`'s scope, the guard's closure is called. //! // It is also called if we exit this scope through unwinding instead. //! } //! # fn main() { //! # f(); //! # } //! ``` //! //! ## `defer!` //! //! Use the `defer` macro to run an operation at scope exit, //! either regular scope exit or during unwinding from a panic. //! //! ``` //! #[macro_use(defer)] extern crate scopeguard; //! //! use std::cell::Cell; //! //! fn main() { //! // use a cell to observe drops during and after the scope guard is active //! let drop_counter = Cell::new(0); //! { //! // Create a scope guard using `defer!` for the current scope //! defer! { //! drop_counter.set(1 + drop_counter.get()); //! } //! //! // Do regular operations here in the meantime. //! //! // Just before scope exit: it hasn't run yet. //! assert_eq!(drop_counter.get(), 0); //! //! // The following scope end is where the defer closure is called //! } //! assert_eq!(drop_counter.get(), 1); //! } //! ``` //! //! ## Scope Guard with Value //! //! If the scope guard closure needs to access an outer value that is also //! mutated outside of the scope guard, then you may want to use the scope guard //! with a value. The guard works like a smart pointer, so the inner value can //! be accessed by reference or by mutable reference. //! //! ### 1. The guard owns a file //! //! In this example, the scope guard owns a file and ensures pending writes are //! synced at scope exit. //! //! ``` //! extern crate scopeguard; //! //! use std::fs::*; //! use std::io::{self, Write}; //! # // Mock file so that we don't actually write a file //! # struct MockFile; //! # impl MockFile { //! # fn create(_s: &str) -> io::Result { Ok(MockFile) } //! # fn write_all(&self, _b: &[u8]) -> io::Result<()> { Ok(()) } //! # fn sync_all(&self) -> io::Result<()> { Ok(()) } //! # } //! # use self::MockFile as File; //! //! fn try_main() -> io::Result<()> { //! let f = File::create("newfile.txt")?; //! let mut file = scopeguard::guard(f, |f| { //! // ensure we flush file at return or panic //! let _ = f.sync_all(); //! }); //! // Access the file through the scope guard itself //! file.write_all(b"test me\n").map(|_| ()) //! } //! //! fn main() { //! try_main().unwrap(); //! } //! //! ``` //! //! ### 2. The guard restores an invariant on scope exit //! //! ``` //! extern crate scopeguard; //! //! use std::mem::ManuallyDrop; //! use std::ptr; //! //! // This function, just for this example, takes the first element //! // and inserts it into the assumed sorted tail of the vector. //! // //! // For optimization purposes we temporarily violate an invariant of the //! // Vec, that it owns all of its elements. //! // //! // The safe approach is to use swap, which means two writes to memory, //! // the optimization is to use a “hole” which uses only one write of memory //! // for each position it moves. //! // //! // We *must* use a scope guard to run this code safely. We //! // are running arbitrary user code (comparison operators) that may panic. //! // The scope guard ensures we restore the invariant after successful //! // exit or during unwinding from panic. //! fn insertion_sort_first(v: &mut Vec) //! where T: PartialOrd //! { //! struct Hole<'a, T: 'a> { //! v: &'a mut Vec, //! index: usize, //! value: ManuallyDrop, //! } //! //! unsafe { //! // Create a moved-from location in the vector, a “hole”. //! let value = ptr::read(&v[0]); //! let mut hole = Hole { v: v, index: 0, value: ManuallyDrop::new(value) }; //! //! // Use a scope guard with a value. //! // At scope exit, plug the hole so that the vector is fully //! // initialized again. //! // The scope guard owns the hole, but we can access it through the guard. //! let mut hole_guard = scopeguard::guard(hole, |hole| { //! // plug the hole in the vector with the value that was // taken out //! let index = hole.index; //! ptr::copy_nonoverlapping(&*hole.value, &mut hole.v[index], 1); //! }); //! //! // run algorithm that moves the hole in the vector here //! // move the hole until it's in a sorted position //! for i in 1..hole_guard.v.len() { //! if *hole_guard.value >= hole_guard.v[i] { //! // move the element back and the hole forward //! let index = hole_guard.index; //! hole_guard.v.swap(index, index + 1); //! hole_guard.index += 1; //! } else { //! break; //! } //! } //! //! // When the scope exits here, the Vec becomes whole again! //! } //! } //! //! fn main() { //! let string = String::from; //! let mut data = vec![string("c"), string("a"), string("b"), string("d")]; //! insertion_sort_first(&mut data); //! assert_eq!(data, vec!["a", "b", "c", "d"]); //! } //! //! ``` //! //! //! # Crate Features //! //! - `use_std` //! + Enabled by default. Enables the `OnUnwind` and `OnSuccess` strategies. //! + Disable to use `no_std`. //! //! # Rust Version //! //! This version of the crate requires Rust 1.20 or later. //! //! The scopeguard 1.x release series will use a carefully considered version //! upgrade policy, where in a later 1.x version, we will raise the minimum //! required Rust version. #[cfg(not(any(test, feature = "use_std")))] extern crate core as std; use std::fmt; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr; /// Controls in which cases the associated code should be run pub trait Strategy { /// Return `true` if the guard’s associated code should run /// (in the context where this method is called). fn should_run() -> bool; } /// Always run on scope exit. /// /// “Always” run: on regular exit from a scope or on unwinding from a panic. /// Can not run on abort, process exit, and other catastrophic events where /// destructors don’t run. #[derive(Debug)] pub enum Always {} /// Run on scope exit through unwinding. /// /// Requires crate feature `use_std`. #[cfg(feature = "use_std")] #[derive(Debug)] pub enum OnUnwind {} /// Run on regular scope exit, when not unwinding. /// /// Requires crate feature `use_std`. #[cfg(feature = "use_std")] #[derive(Debug)] pub enum OnSuccess {} impl Strategy for Always { #[inline(always)] fn should_run() -> bool { true } } #[cfg(feature = "use_std")] impl Strategy for OnUnwind { #[inline] fn should_run() -> bool { std::thread::panicking() } } #[cfg(feature = "use_std")] impl Strategy for OnSuccess { #[inline] fn should_run() -> bool { !std::thread::panicking() } } /// Macro to create a `ScopeGuard` (always run). /// /// The macro takes statements, which are the body of a closure /// that will run when the scope is exited. #[macro_export] macro_rules! defer { ($($t:tt)*) => { let _guard = $crate::guard((), |()| { $($t)* }); }; } /// Macro to create a `ScopeGuard` (run on successful scope exit). /// /// The macro takes statements, which are the body of a closure /// that will run when the scope is exited. /// /// Requires crate feature `use_std`. #[cfg(feature = "use_std")] #[macro_export] macro_rules! defer_on_success { ($($t:tt)*) => { let _guard = $crate::guard_on_success((), |()| { $($t)* }); }; } /// Macro to create a `ScopeGuard` (run on unwinding from panic). /// /// The macro takes statements, which are the body of a closure /// that will run when the scope is exited. /// /// Requires crate feature `use_std`. #[cfg(feature = "use_std")] #[macro_export] macro_rules! defer_on_unwind { ($($t:tt)*) => { let _guard = $crate::guard_on_unwind((), |()| { $($t)* }); }; } /// `ScopeGuard` is a scope guard that may own a protected value. /// /// If you place a guard in a local variable, the closure can /// run regardless how you leave the scope — through regular return or panic /// (except if panic or other code aborts; so as long as destructors run). /// It is run only once. /// /// The `S` parameter for [`Strategy`](trait.Strategy.html) determines if /// the closure actually runs. /// /// The guard's closure will be called with the held value in the destructor. /// /// The `ScopeGuard` implements `Deref` so that you can access the inner value. pub struct ScopeGuard where F: FnOnce(T), S: Strategy, { value: ManuallyDrop, dropfn: ManuallyDrop, // fn(S) -> S is used, so that the S is not taken into account for auto traits. strategy: PhantomData S>, } impl ScopeGuard where F: FnOnce(T), S: Strategy, { /// Create a `ScopeGuard` that owns `v` (accessible through deref) and calls /// `dropfn` when its destructor runs. /// /// The `Strategy` decides whether the scope guard's closure should run. #[inline] #[must_use] pub fn with_strategy(v: T, dropfn: F) -> ScopeGuard { ScopeGuard { value: ManuallyDrop::new(v), dropfn: ManuallyDrop::new(dropfn), strategy: PhantomData, } } /// “Defuse” the guard and extract the value without calling the closure. /// /// ``` /// extern crate scopeguard; /// /// use scopeguard::{guard, ScopeGuard}; /// /// fn conditional() -> bool { true } /// /// fn main() { /// let mut guard = guard(Vec::new(), |mut v| v.clear()); /// guard.push(1); /// /// if conditional() { /// // a condition maybe makes us decide to /// // “defuse” the guard and get back its inner parts /// let value = ScopeGuard::into_inner(guard); /// } else { /// // guard still exists in this branch /// } /// } /// ``` #[inline] pub fn into_inner(guard: Self) -> T { // Cannot move out of `Drop`-implementing types, // so `ptr::read` the value and forget the guard. let mut guard = ManuallyDrop::new(guard); unsafe { let value = ptr::read(&*guard.value); // Drop the closure after `value` has been read, so that if the // closure's `drop` function panics, unwinding still tries to drop // `value`. ManuallyDrop::drop(&mut guard.dropfn); value } } } /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. #[inline] #[must_use] pub fn guard(v: T, dropfn: F) -> ScopeGuard where F: FnOnce(T), { ScopeGuard::with_strategy(v, dropfn) } /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. /// /// Requires crate feature `use_std`. #[cfg(feature = "use_std")] #[inline] #[must_use] pub fn guard_on_success(v: T, dropfn: F) -> ScopeGuard where F: FnOnce(T), { ScopeGuard::with_strategy(v, dropfn) } /// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. /// /// Requires crate feature `use_std`. /// /// ## Examples /// /// For performance reasons, or to emulate “only run guard on unwind” in /// no-std environments, we can also use the default guard and simply manually /// defuse it at the end of scope like the following example. (The performance /// reason would be if the [`OnUnwind`]'s call to [std::thread::panicking()] is /// an issue.) /// /// ``` /// extern crate scopeguard; /// /// use scopeguard::ScopeGuard; /// # fn main() { /// { /// let guard = scopeguard::guard((), |_| {}); /// /// // rest of the code here /// /// // we reached the end of scope without unwinding - defuse it /// ScopeGuard::into_inner(guard); /// } /// # } /// ``` #[cfg(feature = "use_std")] #[inline] #[must_use] pub fn guard_on_unwind(v: T, dropfn: F) -> ScopeGuard where F: FnOnce(T), { ScopeGuard::with_strategy(v, dropfn) } // ScopeGuard can be Sync even if F isn't because the closure is // not accessible from references. // The guard does not store any instance of S, so it is also irrelevant. unsafe impl Sync for ScopeGuard where T: Sync, F: FnOnce(T), S: Strategy, { } impl Deref for ScopeGuard where F: FnOnce(T), S: Strategy, { type Target = T; fn deref(&self) -> &T { &*self.value } } impl DerefMut for ScopeGuard where F: FnOnce(T), S: Strategy, { fn deref_mut(&mut self) -> &mut T { &mut *self.value } } impl Drop for ScopeGuard where F: FnOnce(T), S: Strategy, { fn drop(&mut self) { // This is OK because the fields are `ManuallyDrop`s // which will not be dropped by the compiler. let (value, dropfn) = unsafe { (ptr::read(&*self.value), ptr::read(&*self.dropfn)) }; if S::should_run() { dropfn(value); } } } impl fmt::Debug for ScopeGuard where T: fmt::Debug, F: FnOnce(T), S: Strategy, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct(stringify!(ScopeGuard)) .field("value", &*self.value) .finish() } } #[cfg(test)] mod tests { use super::*; use std::cell::Cell; use std::panic::catch_unwind; use std::panic::AssertUnwindSafe; #[test] fn test_defer() { let drops = Cell::new(0); defer!(drops.set(1000)); assert_eq!(drops.get(), 0); } #[cfg(feature = "use_std")] #[test] fn test_defer_success_1() { let drops = Cell::new(0); { defer_on_success!(drops.set(1)); assert_eq!(drops.get(), 0); } assert_eq!(drops.get(), 1); } #[cfg(feature = "use_std")] #[test] fn test_defer_success_2() { let drops = Cell::new(0); let _ = catch_unwind(AssertUnwindSafe(|| { defer_on_success!(drops.set(1)); panic!("failure") })); assert_eq!(drops.get(), 0); } #[cfg(feature = "use_std")] #[test] fn test_defer_unwind_1() { let drops = Cell::new(0); let _ = catch_unwind(AssertUnwindSafe(|| { defer_on_unwind!(drops.set(1)); assert_eq!(drops.get(), 0); panic!("failure") })); assert_eq!(drops.get(), 1); } #[cfg(feature = "use_std")] #[test] fn test_defer_unwind_2() { let drops = Cell::new(0); { defer_on_unwind!(drops.set(1)); } assert_eq!(drops.get(), 0); } #[test] fn test_only_dropped_by_closure_when_run() { let value_drops = Cell::new(0); let value = guard((), |()| value_drops.set(1 + value_drops.get())); let closure_drops = Cell::new(0); let guard = guard(value, |_| closure_drops.set(1 + closure_drops.get())); assert_eq!(value_drops.get(), 0); assert_eq!(closure_drops.get(), 0); drop(guard); assert_eq!(value_drops.get(), 1); assert_eq!(closure_drops.get(), 1); } #[cfg(feature = "use_std")] #[test] fn test_dropped_once_when_not_run() { let value_drops = Cell::new(0); let value = guard((), |()| value_drops.set(1 + value_drops.get())); let captured_drops = Cell::new(0); let captured = guard((), |()| captured_drops.set(1 + captured_drops.get())); let closure_drops = Cell::new(0); let guard = guard_on_unwind(value, |value| { drop(value); drop(captured); closure_drops.set(1 + closure_drops.get()) }); assert_eq!(value_drops.get(), 0); assert_eq!(captured_drops.get(), 0); assert_eq!(closure_drops.get(), 0); drop(guard); assert_eq!(value_drops.get(), 1); assert_eq!(captured_drops.get(), 1); assert_eq!(closure_drops.get(), 0); } #[test] fn test_into_inner() { let dropped = Cell::new(false); let value = guard(42, |_| dropped.set(true)); let guard = guard(value, |_| dropped.set(true)); let inner = ScopeGuard::into_inner(guard); assert_eq!(dropped.get(), false); assert_eq!(*inner, 42); } }