replace_drop/lib.rs
1//! ReplaceDrop replaces the drop of a type
2//!
3//! It wraps ManuallyDrop and instead of not calling drop, it calls a secondary one
4//! This allows you to use other crates like ext to override the drop function of a type
5
6use std::{
7 mem::ManuallyDrop,
8 ops::{Deref, DerefMut},
9};
10
11/// # Safety
12/// The implemenentor must ensure that they do not remove any drop functionality that is important
13/// When using ReplaceDrop, the struct's fields to not automatically get dropped
14pub unsafe trait ReplaceDropImpl {
15 /// # Safety
16 /// The caller must ensure this function is only called once
17 unsafe fn drop(&mut self);
18}
19
20// SAFETY: Unit type does not have a default drop
21unsafe impl ReplaceDropImpl for () {
22 unsafe fn drop(&mut self) {}
23}
24
25/// A wrapper around ManuallyDrop that instead of removing the drop, replaces it
26/// Example:
27/// ```
28/// use replace_drop::{ReplaceDropImpl, ReplaceDrop};
29/// struct MyData { data: i32 }
30/// unsafe impl ReplaceDropImpl for MyData {
31/// unsafe fn drop(&mut self) {
32/// println!("Called drop with {}", self.data)
33/// }
34/// }
35///
36/// # fn main() {
37/// let data = MyData {data: 3};
38/// let data2 = MyData {data: 3};
39
40/// drop(data); // Prints nothing
41/// let data_replace_drop = ReplaceDrop::new(data2);
42/// drop(data_replace_drop); // Prints "Called drop with 3"
43
44/// # }
45
46/// ```
47#[derive(Clone, Debug)]
48pub struct ReplaceDrop<T: ReplaceDropImpl>(ManuallyDrop<T>);
49
50impl<T: ReplaceDropImpl> ReplaceDrop<T> {
51 #[must_use = "use `replace_drop::replace_drop` to clarify the intent: replace_drop(val);"]
52 pub fn new(val: T) -> Self {
53 ReplaceDrop(ManuallyDrop::new(val))
54 }
55
56 #[must_use = "use `replace_drop::replace_drop` to clarify the intent: replace_drop(val);"]
57 pub fn new_from_manually_drop(val: ManuallyDrop<T>) -> Self {
58 ReplaceDrop(val)
59 }
60
61 pub fn into_inner(mut self) -> T {
62 // SAFETY: We immediatly mem::forget(self) after this so self.0 cant be used
63 let val = unsafe { ManuallyDrop::take(&mut self.0) };
64 std::mem::forget(self);
65 val
66 }
67}
68
69impl<T: ReplaceDropImpl> Drop for ReplaceDrop<T> {
70 fn drop(&mut self) {
71 // SAFETY: This is called in the Drop implementation, so it can't be called multiple times with the same value
72 unsafe { ReplaceDropImpl::drop(self.0.deref_mut()) };
73 }
74}
75
76impl<T: ReplaceDropImpl> Deref for ReplaceDrop<T> {
77 type Target = T;
78
79 fn deref(&self) -> &Self::Target {
80 &self.0
81 }
82}
83
84impl<T: ReplaceDropImpl> DerefMut for ReplaceDrop<T> {
85 fn deref_mut(&mut self) -> &mut Self::Target {
86 &mut self.0
87 }
88}
89
90/// Works like drop(val) but uses the ReplaceDropImpl
91/// Example:
92/// ```
93/// use replace_drop::{ReplaceDropImpl, replace_drop};
94/// struct MyData { data: i32 }
95/// unsafe impl ReplaceDropImpl for MyData {
96/// unsafe fn drop(&mut self) {
97/// println!("Called replace_drop with {}", self.data)
98/// }
99/// }
100///
101/// # fn main() {
102/// let data = MyData {data: 3};
103/// let data2 = MyData {data: 3};
104
105/// drop(data); // Prints nothing
106/// replace_drop(data2); // Prints "Called replace_drop with 3"
107
108/// # }
109/// ```
110pub fn replace_drop<T: ReplaceDropImpl>(val: T) {
111 let _ = ReplaceDrop::new(val);
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn test() {
120 struct MyType<'a>(&'a mut u32);
121 impl<'a> Drop for MyType<'a> {
122 fn drop(&mut self) {
123 *self.0 = 1;
124 }
125 }
126
127 unsafe impl<'a> ReplaceDropImpl for MyType<'a> {
128 unsafe fn drop(&mut self) {
129 *self.0 = 5;
130 }
131 }
132
133 let mut t = 0;
134
135 drop(ReplaceDrop::new(MyType(&mut t)));
136 assert_eq!(t, 5);
137
138 drop(MyType(&mut t));
139
140 assert_eq!(t, 1);
141
142 replace_drop(MyType(&mut t));
143
144 assert_eq!(t, 5);
145 }
146}