scopeguard_lite/
lib.rs

1//! A lightweight way to defer execution of a block to the end of the scope, and
2//! to run code during an unwind.
3//!
4//! This crate provides the [`defer!`] macro and [`Defer`] RAII guard.
5//!
6//! This crate is extremely lightweight: it has no external dependencies or build
7//! scripts, and <150 LOC.
8//!
9//! # Notes
10//!
11//! ## Drop Order
12//! In Rust, local variables are always dropped in **reverse** declaration order.  
13//! ie. the following program prints `012`:
14//! ```rust
15//! # use scopeguard_lite::defer;
16//! defer! { print!("2"); }
17//! defer! { print!("1"); }
18//! print!("0");
19//! ```
20//! That is to say, the *first* scopeguard you define in a scope is the one
21//! that runs *last*.
22//!
23//! # Rust Version
24//!
25//! The current MSRV is `1.61`. While unlikely, it may increase in a future minor
26//! release.
27
28#![no_std]
29#![allow(unknown_lints)]
30#![warn(missing_debug_implementations)]
31#![warn(missing_docs)]
32#![warn(unnameable_types)]
33#![warn(unreachable_pub)]
34#![deny(elided_lifetimes_in_paths)]
35#![deny(unsafe_op_in_unsafe_fn)]
36#![forbid(non_ascii_idents)]
37
38use core::any::type_name;
39use core::mem::ManuallyDrop;
40use core::{fmt, mem};
41
42/// Defers execution of the enclosed code until the end of scope. The code will
43/// run when the current scope ends, regardless of how that happens (panic, return, etc).
44///
45/// For more information, see the [crate docs](crate).
46///
47/// # Expansion
48///
49/// This macro expands to a single statement:
50/// ```rust
51/// let _guard = ::scopeguard_lite::Defer::new(|| { /* your code here */ });
52/// ```
53///
54/// Macro hygiene prevents you from naming the `_guard` variable. If you need
55/// to conditionally defuse the guard, create a [`Defer`] guard manually with
56/// [`Defer::new`], assign it to a variable, then call [`.defuse()`](Defer::defuse)
57/// on the code paths you do *not* want it to execute on.
58///
59/// # Examples
60///
61/// Drop a value, then deallocate it (even if the dtor panics!):
62/// ```
63/// # use scopeguard_lite::defer;
64/// # use std::{ptr, alloc::{dealloc, Layout}};
65/// unsafe fn destroy<T: ?Sized>(ptr: *mut T) {
66///     # // FIXME(feature layout_for_ptr #69835): `Layout::for_value(&*ptr)` -> `Layout::for_value_raw(ptr)`
67///     // avoid memory leaks by ensuring the backing storage is
68///     // always deallocated, even if the destructor panics
69///     defer! { dealloc(ptr.cast(), Layout::for_value(&*ptr)) }
70///     ptr::drop_in_place(ptr);
71/// }
72/// ```
73#[macro_export]
74macro_rules! defer {
75    ($($tt:tt)*) => {
76        let _guard = $crate::Defer::new(|| { $($tt)* });
77    };
78}
79
80/// Execute a closure on drop.
81///
82/// # Examples
83///
84/// This program prints `01`:
85/// ```
86/// # use scopeguard_lite::Defer;
87/// fn foo() {
88///     let guard = Defer::new(|| print!("1"));
89///     print!("0");
90/// } // <- guard dropped here
91/// ```
92#[repr(transparent)]
93pub struct Defer<F: FnOnce()> {
94    f: ManuallyDrop<F>,
95}
96
97impl<F: FnOnce()> Defer<F> {
98    /// Creates a new guard that will executed the provided closure when it is
99    /// dropped.
100    #[inline]
101    #[must_use = "the closure will execute immediately if unused"]
102    pub const fn new(f: F) -> Self {
103        Defer {
104            f: ManuallyDrop::new(f),
105        }
106    }
107
108    /// "Defuses" this scope guard, preventing the closure from running.
109    ///
110    /// For more information, see the [crate docs](crate).
111    ///
112    /// # Notes
113    ///
114    /// This will drop the closure (and all of its captures).
115    ///
116    /// # Examples
117    ///
118    /// ```
119    /// # use scopeguard_lite::Defer;
120    /// let guard = Defer::new(|| unreachable!("never executed"));
121    /// guard.defuse();
122    /// ```
123    #[inline]
124    pub fn defuse(mut self) {
125        unsafe { ManuallyDrop::drop(&mut self.f) };
126        mem::forget(self);
127    }
128}
129
130impl<F: FnOnce()> Drop for Defer<F> {
131    #[inline]
132    fn drop(&mut self) {
133        let f = unsafe { ManuallyDrop::take(&mut self.f) };
134        f();
135    }
136}
137
138// perhaps debuggers or REPLs can take advantage of this
139impl<F: FnOnce()> fmt::Debug for Defer<F> {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        f.pad(type_name::<Self>())
142    }
143}