oxidd_core/util/
on_drop.rs

1use std::mem::ManuallyDrop;
2use std::ops::{Deref, DerefMut};
3
4use crate::Manager;
5
6use crate::util::DropWith;
7
8/// `OnDrop::new(data, f)` executes `f(data)` when dropped
9///
10/// This simplifies writing actions to be executed when unwinding.
11#[derive(Debug)]
12pub struct OnDrop<'a, T, D: FnOnce(&mut T)>(ManuallyDrop<(&'a mut T, D)>);
13
14impl<'a, T, D: FnOnce(&mut T)> OnDrop<'a, T, D> {
15    /// Create a new `OnDrop` handler
16    #[inline(always)]
17    pub fn new(data: &'a mut T, drop_handler: D) -> Self {
18        Self(ManuallyDrop::new((data, drop_handler)))
19    }
20
21    /// Access the data
22    #[inline(always)]
23    pub fn data(&self) -> &T {
24        self.0 .0
25    }
26
27    /// Access the data
28    #[inline(always)]
29    pub fn data_mut(&mut self) -> &mut T {
30        self.0 .0
31    }
32
33    /// Cancel the handler
34    #[inline(always)]
35    pub fn cancel(mut self) -> (&'a mut T, D) {
36        // SAFETY: we destruct/drop `self`, so it cannot be accessed afterwards
37        unsafe { ManuallyDrop::take(&mut self.0) }
38    }
39}
40
41impl<T, D: FnOnce(&mut T)> Drop for OnDrop<'_, T, D> {
42    #[inline(always)]
43    fn drop(&mut self) {
44        // SAFETY: we drop `self`, so it cannot be accessed afterwards
45        let (data, handler) = unsafe { ManuallyDrop::take(&mut self.0) };
46        handler(data)
47    }
48}
49
50/// Zero-sized struct that calls [`std::process::abort()`] if dropped
51///
52/// This is useful to make code exception safe. If there is a region that must
53/// not panic for safety reasons, you can use this to prevent further unwinding,
54/// at least.
55///
56/// Before aborting, the provided string is printed. If the guarded code in the
57/// example panics, `FATAL: Foo panicked. Aborting.` will be printed to stderr.
58///
59/// ## Example
60///
61/// ```
62/// # use oxidd_core::util::AbortOnDrop;
63/// let panic_guard = AbortOnDrop("Foo panicked.");
64/// // ... code that might panic ...
65/// panic_guard.defuse();
66/// ```
67#[derive(Debug)]
68pub struct AbortOnDrop<'a>(pub &'a str);
69
70impl AbortOnDrop<'_> {
71    /// Consume `self` without aborting the process.
72    ///
73    /// Equivalent to `std::mem::forget(self)`.
74    #[inline(always)]
75    pub fn defuse(self) {
76        std::mem::forget(self);
77    }
78}
79
80impl Drop for AbortOnDrop<'_> {
81    fn drop(&mut self) {
82        eprintln!("FATAL: {} Aborting.", self.0);
83        std::process::abort();
84    }
85}
86
87/// Drop guard for edges to ensure that they are not leaked
88pub struct EdgeDropGuard<'a, M: Manager> {
89    /// Manager containing the edge
90    pub manager: &'a M,
91    edge: ManuallyDrop<M::Edge>,
92}
93
94impl<'a, M: Manager> EdgeDropGuard<'a, M> {
95    /// Create a new drop guard
96    #[inline]
97    pub fn new(manager: &'a M, edge: M::Edge) -> Self {
98        Self {
99            manager,
100            edge: ManuallyDrop::new(edge),
101        }
102    }
103
104    /// Convert `this` into the contained edge
105    #[inline]
106    pub fn into_edge(mut self) -> M::Edge {
107        // SAFETY: `this.edge` is never used again, we drop `this` below
108        let edge = unsafe { ManuallyDrop::take(&mut self.edge) };
109        std::mem::forget(self);
110        edge
111    }
112}
113
114impl<'a, M: Manager> Drop for EdgeDropGuard<'a, M> {
115    #[inline]
116    fn drop(&mut self) {
117        // SAFETY: `self.edge` is never used again.
118        self.manager
119            .drop_edge(unsafe { ManuallyDrop::take(&mut self.edge) });
120    }
121}
122
123impl<'a, M: Manager> Deref for EdgeDropGuard<'a, M> {
124    type Target = M::Edge;
125
126    #[inline]
127    fn deref(&self) -> &Self::Target {
128        &self.edge
129    }
130}
131impl<'a, M: Manager> DerefMut for EdgeDropGuard<'a, M> {
132    #[inline]
133    fn deref_mut(&mut self) -> &mut Self::Target {
134        &mut self.edge
135    }
136}
137
138/// Drop guard for vectors of edges to ensure that they are not leaked
139pub struct EdgeVecDropGuard<'a, M: Manager> {
140    /// Manager containing the edges
141    pub manager: &'a M,
142    vec: Vec<M::Edge>,
143}
144
145impl<'a, M: Manager> EdgeVecDropGuard<'a, M> {
146    /// Create a new drop guard
147    #[inline]
148    pub fn new(manager: &'a M, vec: Vec<M::Edge>) -> Self {
149        Self { manager, vec }
150    }
151
152    /// Convert `this` into the contained edge
153    #[inline]
154    pub fn into_vec(mut self) -> Vec<M::Edge> {
155        std::mem::take(&mut self.vec)
156    }
157}
158
159impl<'a, M: Manager> Drop for EdgeVecDropGuard<'a, M> {
160    #[inline]
161    fn drop(&mut self) {
162        for e in std::mem::take(&mut self.vec) {
163            self.manager.drop_edge(e);
164        }
165    }
166}
167
168impl<'a, M: Manager> Deref for EdgeVecDropGuard<'a, M> {
169    type Target = Vec<M::Edge>;
170
171    #[inline]
172    fn deref(&self) -> &Self::Target {
173        &self.vec
174    }
175}
176impl<'a, M: Manager> DerefMut for EdgeVecDropGuard<'a, M> {
177    #[inline]
178    fn deref_mut(&mut self) -> &mut Self::Target {
179        &mut self.vec
180    }
181}
182
183/// Drop guard for inner nodes to ensure that they are not leaked
184pub struct InnerNodeDropGuard<'a, M: Manager> {
185    /// Manager that is used to drop the node in the drop handler
186    pub manager: &'a M,
187    node: ManuallyDrop<M::InnerNode>,
188}
189
190impl<'a, M: Manager> InnerNodeDropGuard<'a, M> {
191    /// Create a new drop guard
192    #[inline]
193    pub fn new(manager: &'a M, node: M::InnerNode) -> Self {
194        Self {
195            manager,
196            node: ManuallyDrop::new(node),
197        }
198    }
199
200    /// Convert `this` into the contained node
201    #[inline]
202    pub fn into_node(mut this: Self) -> M::InnerNode {
203        // SAFETY: `this.edge` is never used again, we drop `this` below
204        let node = unsafe { ManuallyDrop::take(&mut this.node) };
205        std::mem::forget(this);
206        node
207    }
208}
209
210impl<'a, M: Manager> Drop for InnerNodeDropGuard<'a, M> {
211    #[inline]
212    fn drop(&mut self) {
213        // SAFETY: `self.node` is never used again.
214        unsafe { ManuallyDrop::take(&mut self.node) }.drop_with(|e| self.manager.drop_edge(e));
215    }
216}
217
218impl<'a, M: Manager> Deref for InnerNodeDropGuard<'a, M> {
219    type Target = M::InnerNode;
220
221    #[inline]
222    fn deref(&self) -> &Self::Target {
223        &self.node
224    }
225}
226impl<'a, M: Manager> DerefMut for InnerNodeDropGuard<'a, M> {
227    #[inline]
228    fn deref_mut(&mut self) -> &mut Self::Target {
229        &mut self.node
230    }
231}