Skip to main content

core/mem/
drop_guard.rs

1use crate::fmt::{self, Debug};
2use crate::marker::Destruct;
3use crate::mem::ManuallyDrop;
4use crate::ops::{Deref, DerefMut};
5
6/// Wrap a value and run a closure when dropped.
7///
8/// This is useful for quickly creating destructors inline.
9///
10/// # Examples
11///
12/// ```rust
13/// # #![allow(unused)]
14/// use std::mem::DropGuard;
15///
16/// {
17///     // Create a new guard around a string that will
18///     // print its value when dropped.
19///     let s = String::from("Chashu likes tuna");
20///     let mut s = DropGuard::new(s, |s| println!("{s}"));
21///
22///     // Modify the string contained in the guard.
23///     s.push_str("!!!");
24///
25///     // The guard will be dropped here, printing:
26///     // "Chashu likes tuna!!!"
27/// }
28/// ```
29#[stable(feature = "drop_guard", since = "1.100.0")]
30#[doc(alias = "ScopeGuard")]
31#[doc(alias = "defer")]
32#[rustc_diagnostic_item = "DropGuard"]
33pub struct DropGuard<#[rustc_assert_variance(covariant)] T, #[rustc_assert_variance(covariant)] F>
34where
35    F: FnOnce(T),
36{
37    inner: ManuallyDrop<T>,
38    f: ManuallyDrop<F>,
39}
40
41impl<T, F> DropGuard<T, F>
42where
43    F: FnOnce(T),
44{
45    /// Create a new instance of `DropGuard`.
46    ///
47    /// # Example
48    ///
49    /// ```rust
50    /// # #![allow(unused)]
51    /// use std::mem::DropGuard;
52    ///
53    /// let value = String::from("Chashu likes tuna");
54    /// let guard = DropGuard::new(value, |s| println!("{s}"));
55    /// ```
56    #[stable(feature = "drop_guard", since = "1.100.0")]
57    #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")]
58    #[must_use]
59    pub const fn new(inner: T, f: F) -> Self {
60        Self { inner: ManuallyDrop::new(inner), f: ManuallyDrop::new(f) }
61    }
62
63    /// Consumes the `DropGuard`, returning the wrapped value.
64    ///
65    /// This will not execute the closure. It is typically preferred to call
66    /// this function instead of `mem::forget` because it will return the stored
67    /// value and drop variables captured by the closure instead of leaking their
68    /// owned resources.
69    ///
70    /// # Example
71    ///
72    /// ```rust
73    /// # #![allow(unused)]
74    /// use std::mem::DropGuard;
75    ///
76    /// let value = String::from("Nori likes chicken");
77    /// let guard = DropGuard::new(value, |s| println!("{s}"));
78    /// assert_eq!(DropGuard::dismiss(guard), "Nori likes chicken");
79    /// ```
80    #[stable(feature = "drop_guard", since = "1.100.0")]
81    #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")]
82    #[inline]
83    pub const fn dismiss(guard: Self) -> T
84    where
85        F: [const] Destruct,
86    {
87        // First we ensure that dropping the guard will not trigger
88        // its destructor
89        let mut guard = ManuallyDrop::new(guard);
90
91        // Next we manually read the stored value from the guard.
92        //
93        // SAFETY: this is safe because we've taken ownership of the guard.
94        let value = unsafe { ManuallyDrop::take(&mut guard.inner) };
95
96        // Finally we drop the stored closure. We do this *after* having read
97        // the value, so that even if the closure's `drop` function panics,
98        // unwinding still tries to drop the value.
99        //
100        // SAFETY: this is safe because we've taken ownership of the guard.
101        unsafe { ManuallyDrop::drop(&mut guard.f) };
102        value
103    }
104}
105
106#[stable(feature = "drop_guard", since = "1.100.0")]
107#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
108const impl<T, F> Deref for DropGuard<T, F>
109where
110    F: FnOnce(T),
111{
112    type Target = T;
113
114    fn deref(&self) -> &T {
115        &self.inner
116    }
117}
118
119#[stable(feature = "drop_guard", since = "1.100.0")]
120#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
121const impl<T, F> DerefMut for DropGuard<T, F>
122where
123    F: FnOnce(T),
124{
125    fn deref_mut(&mut self) -> &mut T {
126        &mut self.inner
127    }
128}
129
130#[stable(feature = "drop_guard", since = "1.100.0")]
131#[rustc_const_unstable(feature = "const_drop_guard", issue = "none")]
132const impl<T, F> Drop for DropGuard<T, F>
133where
134    F: [const] FnOnce(T),
135{
136    fn drop(&mut self) {
137        // SAFETY: `DropGuard` is in the process of being dropped.
138        let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
139
140        // SAFETY: `DropGuard` is in the process of being dropped.
141        let f = unsafe { ManuallyDrop::take(&mut self.f) };
142
143        f(inner);
144    }
145}
146
147#[stable(feature = "drop_guard", since = "1.100.0")]
148impl<T, F> Debug for DropGuard<T, F>
149where
150    T: Debug,
151    F: FnOnce(T),
152{
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        fmt::Debug::fmt(&**self, f)
155    }
156}