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}