core/mem/
drop_guard.rs

1use crate::fmt::{self, Debug};
2use crate::mem::ManuallyDrop;
3use crate::ops::{Deref, DerefMut};
4
5/// Wrap a value and run a closure when dropped.
6///
7/// This is useful for quickly creating destructors inline.
8///
9/// # Examples
10///
11/// ```rust
12/// # #![allow(unused)]
13/// #![feature(drop_guard)]
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#[unstable(feature = "drop_guard", issue = "144426")]
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    /// #![feature(drop_guard)]
52    ///
53    /// use std::mem::DropGuard;
54    ///
55    /// let value = String::from("Chashu likes tuna");
56    /// let guard = DropGuard::new(value, |s| println!("{s}"));
57    /// ```
58    #[unstable(feature = "drop_guard", issue = "144426")]
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    /// #![feature(drop_guard)]
76    ///
77    /// use std::mem::DropGuard;
78    ///
79    /// let value = String::from("Nori likes chicken");
80    /// let guard = DropGuard::new(value, |s| println!("{s}"));
81    /// assert_eq!(guard.dismiss(), "Nori likes chicken");
82    /// ```
83    #[unstable(feature = "drop_guard", issue = "144426")]
84    #[inline]
85    pub fn dismiss(self) -> T {
86        // First we ensure that dropping the guard will not trigger
87        // its destructor
88        let mut this = ManuallyDrop::new(self);
89
90        // Next we manually read the stored value from the guard.
91        //
92        // SAFETY: this is safe because we've taken ownership of the guard.
93        let value = unsafe { ManuallyDrop::take(&mut this.inner) };
94
95        // Finally we drop the stored closure. We do this *after* having read
96        // the value, so that even if the closure's `drop` function panics,
97        // unwinding still tries to drop the value.
98        //
99        // SAFETY: this is safe because we've taken ownership of the guard.
100        unsafe { ManuallyDrop::drop(&mut this.f) };
101        value
102    }
103}
104
105#[unstable(feature = "drop_guard", issue = "144426")]
106impl<T, F> Deref for DropGuard<T, F>
107where
108    F: FnOnce(T),
109{
110    type Target = T;
111
112    fn deref(&self) -> &T {
113        &*self.inner
114    }
115}
116
117#[unstable(feature = "drop_guard", issue = "144426")]
118impl<T, F> DerefMut for DropGuard<T, F>
119where
120    F: FnOnce(T),
121{
122    fn deref_mut(&mut self) -> &mut T {
123        &mut *self.inner
124    }
125}
126
127#[unstable(feature = "drop_guard", issue = "144426")]
128impl<T, F> Drop for DropGuard<T, F>
129where
130    F: FnOnce(T),
131{
132    fn drop(&mut self) {
133        // SAFETY: `DropGuard` is in the process of being dropped.
134        let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
135
136        // SAFETY: `DropGuard` is in the process of being dropped.
137        let f = unsafe { ManuallyDrop::take(&mut self.f) };
138
139        f(inner);
140    }
141}
142
143#[unstable(feature = "drop_guard", issue = "144426")]
144impl<T, F> Debug for DropGuard<T, F>
145where
146    T: Debug,
147    F: FnOnce(T),
148{
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        fmt::Debug::fmt(&**self, f)
151    }
152}