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