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