Skip to main content

polars_utils/
with_drop.rs

1// A copy from the yet unstable library/core/src/mem/drop_guard.rs.
2
3use core::fmt::{self, Debug};
4use core::mem::ManuallyDrop;
5use core::ops::{Deref, DerefMut};
6
7pub struct WithDrop<T, F>
8where
9    F: FnOnce(T),
10{
11    inner: ManuallyDrop<T>,
12    f: ManuallyDrop<F>,
13}
14
15impl<T, F> WithDrop<T, F>
16where
17    F: FnOnce(T),
18{
19    #[must_use]
20    #[inline]
21    pub const fn new(inner: T, f: F) -> Self {
22        Self {
23            inner: ManuallyDrop::new(inner),
24            f: ManuallyDrop::new(f),
25        }
26    }
27
28    #[inline]
29    pub fn dismiss(guard: Self) -> T {
30        // First we ensure that dropping the guard will not trigger
31        // its destructor
32        let mut guard = ManuallyDrop::new(guard);
33
34        // Next we manually read the stored value from the guard.
35        //
36        // SAFETY: this is safe because we've taken ownership of the guard.
37        let value = unsafe { ManuallyDrop::take(&mut guard.inner) };
38
39        // Finally we drop the stored closure. We do this *after* having read
40        // the value, so that even if the closure's `drop` function panics,
41        // unwinding still tries to drop the value.
42        //
43        // SAFETY: this is safe because we've taken ownership of the guard.
44        unsafe { ManuallyDrop::drop(&mut guard.f) };
45        value
46    }
47}
48
49impl<T, F> Deref for WithDrop<T, F>
50where
51    F: FnOnce(T),
52{
53    type Target = T;
54
55    #[inline]
56    fn deref(&self) -> &T {
57        &self.inner
58    }
59}
60
61impl<T, F> DerefMut for WithDrop<T, F>
62where
63    F: FnOnce(T),
64{
65    #[inline]
66    fn deref_mut(&mut self) -> &mut T {
67        &mut self.inner
68    }
69}
70
71impl<T, F> Drop for WithDrop<T, F>
72where
73    F: FnOnce(T),
74{
75    fn drop(&mut self) {
76        // SAFETY: `WithDrop` is in the process of being dropped.
77        let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
78
79        // SAFETY: `WithDrop` is in the process of being dropped.
80        let f = unsafe { ManuallyDrop::take(&mut self.f) };
81
82        f(inner);
83    }
84}
85
86impl<T, F> Debug for WithDrop<T, F>
87where
88    T: Debug,
89    F: FnOnce(T),
90{
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        fmt::Debug::fmt(&**self, f)
93    }
94}