drop_move/lib.rs
1#![warn(missing_docs)]
2#![no_std]
3
4/*!
5
6This crate allows implementing [`Drop`] as "pass by move". Here is an example of how this can be
7used to call a [`FnOnce`] from [`drop`].
8
9```
10use drop_move::{drop_move_wrap, DropMove, DropHandle};
11
12drop_move_wrap! {
13 /// Runs a function when dropped.
14 #[derive(Clone)]
15 pub struct DropGuard<F: FnOnce()>(DropGuardInner {
16 func: F,
17 });
18}
19
20impl<F: FnOnce()> DropMove for DropGuardInner<F> {
21 fn drop_move(self_: DropHandle<Self>) {
22 (DropHandle::into_inner(self_).func)()
23 }
24}
25
26impl<F: FnOnce()> DropGuard<F> {
27 pub fn new(f: F) -> Self {
28 DropGuardInner { func: f }.into()
29 }
30}
31
32let mut x: u32 = 0;
33{
34 let y = Box::new(&mut x); // Box is not Copy, so the closure will only be FnOnce.
35 let guard = DropGuard::new(move || **y += 1);
36}
37
38assert_eq!(x, 1);
39```
40
41By implementing the [`DropMove`] trait, we were able to have `func` run when the `DropGuard` goes
42out of scope. The usual [`Drop`] trait only allows `drop(&mut self)`, which does not allow moving
43the members of the `DropGuard`, as is required to call a [`FnOnce`]. The reason they do not allow
44`drop(self)` is that it would be too easy to accidentally end up dropping `self`, leading to an
45infinite loop. According to Rust's usual semantics `self` would be dropped at the end of the scope,
46and even if a special case were added for `drop(self)` it could still easily happen in a function
47called by `drop`.
48
49These problems are mostly avoided by wrapping `self` in a [`DropHandle`], which will only drop each
50member of the structure when it goes out of scope, rather than calling `drop` recursively.
51Semantically, [`drop_move`](DropMove::drop_move) can be thought of as destructuring `DropGuard`.
52Each unmoved member will be dropped when it goes out of scope. These members can be accessed by
53value through [`into_inner`](DropHandle::into_inner). The original `DropGuard` can be obtained from
54[`into_outer`](DropHandle::into_outer), but you must be careful to avoid infinite recursion when
55using this.
56
57Given this destructuring viewpoint, it should be no surprise that `drop_move` also supports
58destructuring, which is normally not allowed for types that implement [`Drop`]. Here, we can
59convert the `DropGuard` back into the function it contains.
60
61```
62# use drop_move::{drop_move_wrap, DropMove, DropHandle};
63#
64# drop_move_wrap! {
65# #[derive(Clone)]
66# pub struct DropGuard<F: FnOnce()>(DropGuardInner {
67# func: F,
68# });
69# }
70#
71# impl<F: FnOnce()> DropMove for DropGuardInner<F> {
72# fn drop_move(self_: DropHandle<Self>) {
73# (DropHandle::into_inner(self_).func)()
74# }
75# }
76impl<F: FnOnce()> DropGuard<F> {
77 /// Extract the function.
78 pub fn into_inner(self) -> F {
79 let inner: DropGuardInner<F> = self.into();
80 inner.func
81 }
82}
83```
84
85How this works is that [`drop_move_wrap!`] expands into two structure definitions.
86
87```ignore
88# use drop_move::DropMoveWrapper;
89/// Runs a function when dropped.
90#[derive(Clone)]
91pub struct DropGuard<F: FnOnce()>(DropMoveWrapper<DropGuardInner<F>>);
92
93/// Runs a function when dropped.
94#[derive(Clone)]
95struct DropGuardInner<F: FnOnce()> {
96 func: F,
97};
98```
99
100The outer structure `DropGuard` provides the public interface, while `DropGuardInner` contains the
101actual members of the `struct`. Neither will implement [`Drop`]. Instead, [`DropMoveWrapper`] will
102implement [`Drop`] based on the [`DropMove`] you provide. The structure members can be borrowed
103from a `DropGaurd` using `&self.0.func`, because [`DropMoveWrapper`] implements [`Deref`]. They can
104moved by converting the `DropGaurd` to a `DropGuardInner` with
105[`DropMoveWrapper::into_inner(self.0)`](DropMoveWrapper::into_inner) or
106[`self.into()`](Into::into).
107
108Notice that the doc comments and attributes have been duplicated for both structures. In fact, doc
109comments are treated as [attributes](https://stackoverflow.com/a/33999625/4071916) by the compiler.
110
111The macro also creates a few trait implementations.
112
113```
114# use drop_move::{DropMove, DropMoveTypes, DropMoveWrapper, DropHandle};
115# #[derive(Clone)]
116# pub struct DropGuard<F: FnOnce()>(DropMoveWrapper<DropGuardInner<F>>);
117#
118# #[derive(Clone)]
119# struct DropGuardInner<F: FnOnce()> {
120# func: F,
121# };
122#
123impl<F: FnOnce()> From<DropGuard<F>> for DropGuardInner<F> {
124 fn from(x: DropGuard<F>) -> Self {
125 DropMoveWrapper::into_inner(x.0)
126 }
127}
128
129impl<F: FnOnce()> From<DropGuardInner<F>> for DropGuard<F> {
130 fn from(x: DropGuardInner<F>) -> Self {
131 Self(DropMoveWrapper::new(x))
132 }
133}
134
135impl<F: FnOnce()> DropMoveTypes for DropGuardInner<F>
136{
137 type Outer = DropGuard<F>;
138}
139#
140# impl<F: FnOnce()> DropMove for DropGuardInner<F> {
141# fn drop_move(self_: DropHandle<Self>) {
142# (DropHandle::into_inner(self_).func)()
143# }
144# }
145#
146# impl<F: FnOnce()> DropGuard<F> {
147# pub fn new(f: F) -> Self {
148# DropGuard(DropMoveWrapper::new(DropGuardInner { func: f }))
149# }
150# }
151#
152# let mut x: u32 = 0;
153# {
154# let y = Box::new(&mut x);
155# // Box is not Copy, so the closure will only be FnOnce.
156# let guard = DropGuard::new(move || **y += 1);
157# }
158#
159# assert_eq!(x, 1);
160```
161
162The implementation of [`DropMoveTypes`] lets [`DropMoveWrapper`] and [`DropHandle`] know the
163relationship between `DropGuard` and `DropGuardInner`. It is implemented on the inner structure
164because this will keep the implementation private in the common case that the inner structure is
165private but the outer is public. The [`From`] implementations are so that they know how to convert
166back and forth, and also function as convenience methods for creating and destructuring
167`DropGuard`s.
168
169You may be wondering why `drop_move` takes a [`DropHandle`] rather than just passing the inner
170structure `DropGuardInner`, which would behave correctly for destructuring and would drop the
171members individually. However, you wouldn't easily be able to call a `&self` or `&mut self`
172function, which would want an instance of `DropGuard` instead. It would require reconstructing the
173[`DropGuard`] again so that it can be borrowed, then carefully destructuring it after the call to
174avoid infinite `drop` recursion. [`DropHandle`] allows you to avoid this error prone construction
175as it implements [`Deref`] for the outer structure, so you can call its methods directly.
176
177See [`drop_move_wrap!`] for the macro's full supported syntax. See the source for [`DropGuard`] for
178the full example.
179*/
180
181use core::mem;
182use core::ops::Deref;
183use core::ops::DerefMut;
184use mem::ManuallyDrop;
185
186/// Tracks the relationship between an inner `struct` and outer `struct` generated by
187/// [`drop_move_wrap!`].
188///
189/// It is implemented for the inner structure, and `Self::Outer` is set to be the outer structure.
190/// This is separated from [`DropMove`] so that it can be implemented automatically by the macro.
191pub trait DropMoveTypes: Sized + Into<<Self as DropMoveTypes>::Outer>
192where
193 Self::Outer: Into<Self>,
194{
195 /// The corresponding outer structure.
196 type Outer;
197}
198
199/// A variant of [`Drop`] that allows moving out of the value being dropped.
200///
201/// This trait must be implemented by the inner structure generated by [`drop_move_wrap!`].
202pub trait DropMove: DropMoveTypes {
203 /// Drop the value, by move instead of by reference.
204 fn drop_move(self_: DropHandle<Self>) {
205 mem::drop(self_);
206 }
207}
208
209mod drop_handle;
210pub use drop_handle::*;
211
212mod drop_move_wrap;
213pub use drop_move_wrap::*;
214
215mod drop_guard;
216pub use drop_guard::*;
217
218#[cfg(test)]
219mod test {
220 use super::*;
221
222 extern crate std;
223 use core::cell::RefCell;
224 use core::marker::PhantomData;
225 use std::boxed::Box;
226 use std::rc::Rc;
227 use std::vec::Vec;
228
229 drop_move_wrap! {
230 pub struct ReturnToSender<T>(pub ReturnToSenderInner(T, Rc<RefCell<Vec<T>>>))
231 where
232 T: Clone;
233 }
234
235 impl<T: Clone> DropMove for ReturnToSenderInner<T> {
236 fn drop_move(self_: DropHandle<Self>) {
237 let inner = DropHandle::into_inner(self_);
238 inner.1.borrow_mut().push(inner.0);
239 }
240 }
241
242 #[test]
243 fn return_to_sender() {
244 let free_list = Rc::new(RefCell::new(Vec::new()));
245
246 let rts = ReturnToSender::from(ReturnToSenderInner(Box::new(234u32), free_list.clone()));
247 assert!(free_list.borrow().len() == 0);
248
249 mem::drop(rts);
250
251 assert!(free_list.borrow().len() == 1);
252 assert!(*free_list.borrow()[0] == 234);
253 }
254
255 drop_move_wrap! {
256 #[derive(Clone)]
257 {
258 #[derive(PartialEq)]
259 }
260 pub enum WrapStressTest<'a, T: Deref : 'a>(
261 #[derive(PartialOrd)]
262 #[allow(dead_code)]
263 pub(crate) WrapStressTest1 {
264 Foo(PhantomData<&'a ()>),
265 Bar(T),
266 }
267 )
268 where
269 T::Target: 'a;
270 }
271
272 impl<'a, T: Deref> DropMove for WrapStressTest1<'a, T>
273 where
274 T: 'a,
275 T::Target: 'a,
276 {
277 }
278
279 impl<'a, T: Deref> PartialEq for WrapStressTest1<'a, T>
280 where
281 T: 'a,
282 T::Target: 'a,
283 {
284 fn eq(&self, _other: &Self) -> bool {
285 false
286 }
287 }
288}