drop_move/drop_handle.rs
1use super::*;
2
3/// A wrapper of [`T::Outer`](DropMoveTypes::Outer) that will drop by converting to `T` then
4/// dropping, rather than dropping the `T::Outer`.
5///
6/// The trouble with making `drop` be pass by move is that the `self` parameter may end up being
7/// dropped, creating infinite recursion. To avoid this, a `DropHandle` is passed to
8/// [`drop_move`](DropMove::drop_move) so that if it goes out of scope it will not create infinite
9/// recursion. This implements [`Deref`] and [`DerefMut`] for easy access to functions on
10/// `T::Outer`.
11#[derive(Debug)]
12pub struct DropHandle<T: DropMoveTypes>(ManuallyDrop<T::Outer>);
13
14impl<T: DropMoveTypes> DropHandle<T> {
15 unsafe fn take(self_: &mut Self) -> T::Outer {
16 ManuallyDrop::take(&mut self_.0)
17 }
18
19 /// Convert to the inner structure `T`.
20 ///
21 /// This is an associated function so that will not conflict with any methods of `T::Outer`,
22 /// which are accessible through [`Deref`].
23 pub fn into_inner(self_: Self) -> T {
24 Self::into_outer(self_).into()
25 }
26
27 /// Convert to the outer structure `T::Outer`. Be careful when using this function, as it is
28 /// easy to end up recursively calling `drop` on the output by accident, creating an infinite
29 /// recursive loop.
30 ///
31 /// This is an associated function so that will not conflict with any methods of `T::Outer`,
32 /// which are accessible through [`Deref`].
33 pub fn into_outer(mut self_: Self) -> T::Outer {
34 let outer = unsafe { Self::take(&mut self_) };
35 mem::forget(self_);
36 outer
37 }
38}
39
40impl<T: DropMoveTypes> From<T> for DropHandle<T> {
41 fn from(t: T) -> Self {
42 Self(ManuallyDrop::new(t.into()))
43 }
44}
45
46impl<T: DropMoveTypes> Drop for DropHandle<T> {
47 fn drop(&mut self) {
48 let _inner: T = unsafe { Self::take(self) }.into();
49
50 // Dropping the inner type avoids the drop calling drop infinite loop.
51 }
52}
53
54impl<T: DropMoveTypes> Deref for DropHandle<T> {
55 type Target = T::Outer;
56 fn deref(&self) -> &T::Outer {
57 self.0.deref()
58 }
59}
60
61impl<T: DropMoveTypes> DerefMut for DropHandle<T> {
62 fn deref_mut(&mut self) -> &mut T::Outer {
63 self.0.deref_mut()
64 }
65}