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}