Skip to content

Commit 7e1426c

Browse files
committed
Use ManuallyDrop inside Undo
1 parent 16f6f98 commit 7e1426c

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

crates/core/src/undo.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,19 @@ pub struct Undo<T, F>
8282
where
8383
F: FnOnce(T),
8484
{
85-
inner: Option<T>,
86-
undo: Option<F>,
85+
inner: mem::ManuallyDrop<T>,
86+
undo: mem::ManuallyDrop<F>,
8787
}
8888

8989
impl<T, F> Drop for Undo<T, F>
9090
where
9191
F: FnOnce(T),
9292
{
9393
fn drop(&mut self) {
94-
if let Some(inner) = self.inner.take() {
95-
let undo = self.undo.take().unwrap();
96-
undo(inner);
97-
}
94+
// Safety: These `ManuallyDrop` fields will not be used again.
95+
let inner = unsafe { mem::ManuallyDrop::take(&mut self.inner) };
96+
let undo = unsafe { mem::ManuallyDrop::take(&mut self.undo) };
97+
undo(inner);
9898
}
9999
}
100100

@@ -118,7 +118,7 @@ where
118118
type Target = T;
119119

120120
fn deref(&self) -> &Self::Target {
121-
self.inner.as_ref().unwrap()
121+
&self.inner
122122
}
123123
}
124124

@@ -127,7 +127,7 @@ where
127127
F: FnOnce(T),
128128
{
129129
fn deref_mut(&mut self) -> &mut Self::Target {
130-
self.inner.as_mut().unwrap()
130+
&mut self.inner
131131
}
132132
}
133133

@@ -141,16 +141,23 @@ where
141141
/// when dropped, unless the guard is disabled via `Undo::commit`.
142142
pub fn new(inner: T, undo: F) -> Self {
143143
Self {
144-
inner: Some(inner),
145-
undo: Some(undo),
144+
inner: mem::ManuallyDrop::new(inner),
145+
undo: mem::ManuallyDrop::new(undo),
146146
}
147147
}
148148

149149
/// Disable this `Undo` and return its inner value.
150150
///
151151
/// This `Undo`'s cleanup function will never be called.
152152
pub fn commit(mut guard: Self) -> T {
153-
let inner = guard.inner.take().unwrap();
153+
// Safety: These `ManuallyDrop` fields will not be used again.
154+
let inner = unsafe {
155+
// Make sure to drop `undo`, even though we aren't calling it, to
156+
// avoid leaking closed-over `Arc`s, for example.
157+
mem::ManuallyDrop::drop(&mut guard.undo);
158+
159+
mem::ManuallyDrop::take(&mut guard.inner)
160+
};
154161
mem::forget(guard);
155162
inner
156163
}

0 commit comments

Comments
 (0)