1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#![warn(missing_docs)]
#![no_std]

/*!

This crate allows implementing [`Drop`] as "pass by move". Here is an example of how this can be
used to call a [`FnOnce`] from [`drop`].

```
use drop_move::{drop_move_wrap, DropMove, DropHandle};

drop_move_wrap! {
    /// Runs a function when dropped.
    #[derive(Clone)]
    pub struct DropGuard<F: FnOnce()>(DropGuardInner {
        func: F,
    });
}

impl<F: FnOnce()> DropMove for DropGuardInner<F> {
    fn drop_move(self_: DropHandle<Self>) {
        (DropHandle::into_inner(self_).func)()
    }
}

impl<F: FnOnce()> DropGuard<F> {
    pub fn new(f: F) -> Self {
        DropGuardInner { func: f }.into()
    }
}

let mut x: u32 = 0;
{
    let y = Box::new(&mut x); // Box is not Copy, so the closure will only be FnOnce.
    let guard = DropGuard::new(move || **y += 1);
}

assert_eq!(x, 1);
```

By implementing the [`DropMove`] trait, we were able to have `func` run when the `DropGuard` goes
out of scope. The usual [`Drop`] trait only allows `drop(&mut self)`, which does not allow moving
the members of the `DropGuard`, as is required to call a [`FnOnce`]. The reason they do not allow
`drop(self)` is that it would be too easy to accidentally end up dropping `self`, leading to an
infinite loop. According to Rust's usual semantics `self` would be dropped at the end of the scope,
and even if a special case were added for `drop(self)` it could still easily happen in a function
called by `drop`.

These problems are mostly avoided by wrapping `self` in a [`DropHandle`], which will only drop each
member of the structure when it goes out of scope, rather than calling `drop` recursively.
Semantically, [`drop_move`](DropMove::drop_move) can be thought of as destructuring `DropGuard`.
Each unmoved member will be dropped when it goes out of scope. These members can be accessed by
value through [`into_inner`](DropHandle::into_inner). The original `DropGuard` can be obtained from
[`into_outer`](DropHandle::into_outer), but you must be careful to avoid infinite recursion when
using this.

Given this destructuring viewpoint, it should be no surprise that `drop_move` also supports
destructuring, which is normally not allowed for types that implement [`Drop`]. Here, we can
convert the `DropGuard` back into the function it contains.

```
# use drop_move::{drop_move_wrap, DropMove, DropHandle};
#
# drop_move_wrap! {
#     #[derive(Clone)]
#     pub struct DropGuard<F: FnOnce()>(DropGuardInner {
#         func: F,
#     });
# }
#
# impl<F: FnOnce()> DropMove for DropGuardInner<F> {
#     fn drop_move(self_: DropHandle<Self>) {
#         (DropHandle::into_inner(self_).func)()
#     }
# }
impl<F: FnOnce()> DropGuard<F> {
    /// Extract the function.
    pub fn into_inner(self) -> F {
        let inner: DropGuardInner<F> = self.into();
        inner.func
    }
}
```

How this works is that [`drop_move_wrap!`] expands into two structure definitions.

```ignore
# use drop_move::DropMoveWrapper;
/// Runs a function when dropped.
#[derive(Clone)]
pub struct DropGuard<F: FnOnce()>(DropMoveWrapper<DropGuardInner<F>>);

/// Runs a function when dropped.
#[derive(Clone)]
struct DropGuardInner<F: FnOnce()> {
    func: F,
};
```

The outer structure `DropGuard` provides the public interface, while `DropGuardInner` contains the
actual members of the `struct`. Neither will implement [`Drop`]. Instead, [`DropMoveWrapper`] will
implement [`Drop`] based on the [`DropMove`] you provide. The structure members can be borrowed
from a `DropGaurd` using `&self.0.func`, because [`DropMoveWrapper`] implements [`Deref`]. They can
moved by converting the `DropGaurd` to a `DropGuardInner` with
[`DropMoveWrapper::into_inner(self.0)`](DropMoveWrapper::into_inner) or
[`self.into()`](Into::into).

Notice that the doc comments and attributes have been duplicated for both structures. In fact, doc
comments are treated as [attributes](https://stackoverflow.com/a/33999625/4071916) by the compiler.

The macro also creates a few trait implementations.

```
#  use drop_move::{DropMove, DropMoveTypes, DropMoveWrapper, DropHandle};
# #[derive(Clone)]
# pub struct DropGuard<F: FnOnce()>(DropMoveWrapper<DropGuardInner<F>>);
#
# #[derive(Clone)]
# struct DropGuardInner<F: FnOnce()> {
#     func: F,
# };
#
impl<F: FnOnce()> From<DropGuard<F>> for DropGuardInner<F> {
    fn from(x: DropGuard<F>) -> Self {
        DropMoveWrapper::into_inner(x.0)
    }
}

impl<F: FnOnce()> From<DropGuardInner<F>> for DropGuard<F> {
    fn from(x: DropGuardInner<F>) -> Self {
        Self(DropMoveWrapper::new(x))
    }
}

impl<F: FnOnce()> DropMoveTypes for DropGuardInner<F>
{
    type Outer = DropGuard<F>;
}
#
# impl<F: FnOnce()> DropMove for DropGuardInner<F> {
#     fn drop_move(self_: DropHandle<Self>) {
#         (DropHandle::into_inner(self_).func)()
#     }
# }
#
# impl<F: FnOnce()> DropGuard<F> {
#     pub fn new(f: F) -> Self {
#         DropGuard(DropMoveWrapper::new(DropGuardInner { func: f }))
#     }
# }
#
# let mut x: u32 = 0;
# {
#     let y = Box::new(&mut x);
#     // Box is not Copy, so the closure will only be FnOnce.
#     let guard = DropGuard::new(move || **y += 1);
# }
#
# assert_eq!(x, 1);
```

The implementation of [`DropMoveTypes`] lets [`DropMoveWrapper`] and [`DropHandle`] know the
relationship between `DropGuard` and `DropGuardInner`. It is implemented on the inner structure
because this will keep the implementation private in the common case that the inner structure is
private but the outer is public. The [`From`] implementations are so that they know how to convert
back and forth, and also function as convenience methods for creating and destructuring
`DropGuard`s.

You may be wondering why `drop_move` takes a [`DropHandle`] rather than just passing the inner
structure `DropGuardInner`, which would behave correctly for destructuring and would drop the
members individually. However, you wouldn't easily be able to call a `&self` or `&mut self`
function, which would want an instance of `DropGuard` instead. It would require reconstructing the
[`DropGuard`] again so that it can be borrowed, then carefully destructuring it after the call to
avoid infinite `drop` recursion. [`DropHandle`] allows you to avoid this error prone construction
as it implements [`Deref`] for the outer structure, so you can call its methods directly.

See [`drop_move_wrap!`] for the macro's full supported syntax. See the source for [`DropGuard`] for
the full example.
*/

use core::mem;
use core::ops::Deref;
use core::ops::DerefMut;
use mem::ManuallyDrop;

/// Tracks the relationship between an inner `struct` and outer `struct` generated by
/// [`drop_move_wrap!`].
///
/// It is implemented for the inner structure, and `Self::Outer` is set to be the outer structure.
/// This is separated from [`DropMove`] so that it can be implemented automatically by the macro.
pub trait DropMoveTypes: Sized + Into<<Self as DropMoveTypes>::Outer>
where
    Self::Outer: Into<Self>,
{
    /// The corresponding outer structure.
    type Outer;
}

/// A variant of [`Drop`] that allows moving out of the value being dropped.
///
/// This trait must be implemented by the inner structure generated by [`drop_move_wrap!`].
pub trait DropMove: DropMoveTypes {
    /// Drop the value, by move instead of by reference.
    fn drop_move(self_: DropHandle<Self>) {
        mem::drop(self_);
    }
}

mod drop_handle;
pub use drop_handle::*;

mod drop_move_wrap;
pub use drop_move_wrap::*;

mod drop_guard;
pub use drop_guard::*;

#[cfg(test)]
mod test {
    use super::*;

    extern crate std;
    use core::cell::RefCell;
    use core::marker::PhantomData;
    use std::boxed::Box;
    use std::rc::Rc;
    use std::vec::Vec;

    drop_move_wrap! {
        pub struct ReturnToSender<T>(pub ReturnToSenderInner(T, Rc<RefCell<Vec<T>>>))
        where
            T: Clone;
    }

    impl<T: Clone> DropMove for ReturnToSenderInner<T> {
        fn drop_move(self_: DropHandle<Self>) {
            let inner = DropHandle::into_inner(self_);
            inner.1.borrow_mut().push(inner.0);
        }
    }

    #[test]
    fn return_to_sender() {
        let free_list = Rc::new(RefCell::new(Vec::new()));

        let rts = ReturnToSender::from(ReturnToSenderInner(Box::new(234u32), free_list.clone()));
        assert!(free_list.borrow().len() == 0);

        mem::drop(rts);

        assert!(free_list.borrow().len() == 1);
        assert!(*free_list.borrow()[0] == 234);
    }

    drop_move_wrap! {
        #[derive(Clone)]
        {
            #[derive(PartialEq)]
        }
        pub enum WrapStressTest<'a, T: Deref : 'a>(
            #[derive(PartialOrd)]
            #[allow(dead_code)]
            pub(crate) WrapStressTest1 {
                Foo(PhantomData<&'a ()>),
                Bar(T),
            }
        )
        where
            T::Target: 'a;
    }

    impl<'a, T: Deref> DropMove for WrapStressTest1<'a, T>
    where
        T: 'a,
        T::Target: 'a,
    {
    }

    impl<'a, T: Deref> PartialEq for WrapStressTest1<'a, T>
    where
        T: 'a,
        T::Target: 'a,
    {
        fn eq(&self, _other: &Self) -> bool {
            false
        }
    }
}