Skip to main content

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