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}