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