diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/scopeguard/src | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/scopeguard/src')
-rw-r--r-- | third_party/rust/scopeguard/src/lib.rs | 578 |
1 files changed, 578 insertions, 0 deletions
diff --git a/third_party/rust/scopeguard/src/lib.rs b/third_party/rust/scopeguard/src/lib.rs new file mode 100644 index 0000000000..d33c2b69c8 --- /dev/null +++ b/third_party/rust/scopeguard/src/lib.rs @@ -0,0 +1,578 @@ +#![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<Self> { 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<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` 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::{self, 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<T, F, S = Always> + where F: FnOnce(T), + S: Strategy, +{ + value: ManuallyDrop<T>, + dropfn: ManuallyDrop<F>, + // fn(S) -> S is used, so that the S is not taken into account for auto traits. + strategy: PhantomData<fn(S) -> S>, +} + +impl<T, F, S> ScopeGuard<T, F, S> + 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] + pub fn with_strategy(v: T, dropfn: F) -> ScopeGuard<T, F, S> { + 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. + unsafe { + let value = ptr::read(&*guard.value); + // read the closure so that it is dropped, and assign it to a local + // variable to ensure that it is only dropped after the guard has + // been forgotten. (In case the Drop impl of the closure, or that + // of any consumed captured variable, panics). + let _dropfn = ptr::read(&*guard.dropfn); + mem::forget(guard); + value + } + } +} + + +/// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. +#[inline] +pub fn guard<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, Always> + 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] +pub fn guard_on_success<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnSuccess> + 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] +pub fn guard_on_unwind<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnUnwind> + 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<T, F, S> Sync for ScopeGuard<T, F, S> + where T: Sync, + F: FnOnce(T), + S: Strategy +{} + +impl<T, F, S> Deref for ScopeGuard<T, F, S> + where F: FnOnce(T), + S: Strategy +{ + type Target = T; + + fn deref(&self) -> &T { + &*self.value + } +} + +impl<T, F, S> DerefMut for ScopeGuard<T, F, S> + where F: FnOnce(T), + S: Strategy +{ + fn deref_mut(&mut self) -> &mut T { + &mut *self.value + } +} + +impl<T, F, S> Drop for ScopeGuard<T, F, S> + 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<T, F, S> fmt::Debug for ScopeGuard<T, F, S> + 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); + } +} |