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}