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. This is implemented as an associated
67    /// function to prevent any potential conflicts with any other methods called
68    /// `into_inner` from the `Deref` and `DerefMut` impls.
69    ///
70    /// It is typically preferred to call this function instead of `mem::forget`
71    /// because it will return the stored value and drop variables captured
72    /// by the closure instead of leaking their owned resources.
73    ///
74    /// # Example
75    ///
76    /// ```rust
77    /// # #![allow(unused)]
78    /// #![feature(drop_guard)]
79    ///
80    /// use std::mem::DropGuard;
81    ///
82    /// let value = String::from("Nori likes chicken");
83    /// let guard = DropGuard::new(value, |s| println!("{s}"));
84    /// assert_eq!(DropGuard::into_inner(guard), "Nori likes chicken");
85    /// ```
86    #[unstable(feature = "drop_guard", issue = "144426")]
87    #[inline]
88    pub fn into_inner(guard: Self) -> T {
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#[unstable(feature = "drop_guard", issue = "144426")]
109impl<T, F> Deref for DropGuard<T, F>
110where
111    F: FnOnce(T),
112{
113    type Target = T;
114
115    fn deref(&self) -> &T {
116        &*self.inner
117    }
118}
119
120#[unstable(feature = "drop_guard", issue = "144426")]
121impl<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#[unstable(feature = "drop_guard", issue = "144426")]
131impl<T, F> Drop for DropGuard<T, F>
132where
133    F: FnOnce(T),
134{
135    fn drop(&mut self) {
136        // SAFETY: `DropGuard` is in the process of being dropped.
137        let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
138
139        // SAFETY: `DropGuard` is in the process of being dropped.
140        let f = unsafe { ManuallyDrop::take(&mut self.f) };
141
142        f(inner);
143    }
144}
145
146#[unstable(feature = "drop_guard", issue = "144426")]
147impl<T, F> Debug for DropGuard<T, F>
148where
149    T: Debug,
150    F: FnOnce(T),
151{
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        fmt::Debug::fmt(&**self, f)
154    }
155}