Crate scopeguard [−] [src]
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
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::File; use std::io::{self, Write}; 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(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<T>(v: &mut Vec<T>) where T: PartialOrd { struct Hole<'a, T: 'a> { v: &'a mut Vec<T>, index: usize, value: ManuallyDrop<T>, } 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; ptr::copy_nonoverlapping(&hole_guard.v[index + 1], &mut hole_guard.v[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
strategy. - Disable to use
no_std
.
- Enabled by default. Enables the
Macros
defer |
Macro to create a |
defer_on_unwind |
Macro to create a |
Structs
ScopeGuard |
|
Enums
Always |
Always run on scope exit. |
Traits
Strategy |
Functions
guard |
Create a new |