drop_move/
drop_move_wrap.rs

1use super::*;
2
3/// A wrapper around the inner structure `T` that calls [`drop_move`](DropMove::drop_move) when it
4/// is dropped.
5///
6/// The inner structure members can be borrowed using the [`Deref`] and [`DerefMut`]
7/// implementations, or be moved with `into_inner`.
8#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct DropMoveWrapper<T: DropMove>(ManuallyDrop<T>);
10
11impl<T: DropMove> DropMoveWrapper<T> {
12    unsafe fn take(self_: &mut Self) -> T {
13        ManuallyDrop::take(&mut self_.0)
14    }
15
16    /// Wrap the inner structure, so that it will be dropped with `drop_move`.
17    pub fn new(x: T) -> Self {
18        DropMoveWrapper(ManuallyDrop::new(x))
19    }
20
21    /// Convert into the inner structure `T`.
22    ///
23    /// This is an associated function so that will not conflict with any methods of the inner type,
24    /// which are accessible through [`Deref`].
25    pub fn into_inner(mut self_: Self) -> T {
26        let inner = unsafe { Self::take(&mut self_) };
27        mem::forget(self_);
28        inner
29    }
30}
31
32impl<T: DropMove> Deref for DropMoveWrapper<T> {
33    type Target = T;
34    fn deref(&self) -> &Self::Target {
35        self.0.deref()
36    }
37}
38
39impl<T: DropMove> DerefMut for DropMoveWrapper<T> {
40    fn deref_mut(&mut self) -> &mut Self::Target {
41        self.0.deref_mut()
42    }
43}
44
45impl<T: DropMove> Drop for DropMoveWrapper<T> {
46    fn drop(&mut self) {
47        let drop_ref: DropHandle<T> = From::from(unsafe { Self::take(self) });
48        DropMove::drop_move(drop_ref);
49    }
50}
51
52/** Generate a pair of structures to allow moving out of `drop`.
53
54    The syntax is roughly:
55    ```ignore
56    #[shared_attributes]
57    {
58        #[outer_only_attributes]
59    }
60    outer_visibility struct outer_name<...>(
61        #[inner_only_attributes] inner_visibility inner_structure {
62            members
63        }
64    ) where ...;
65    ```
66
67    Tuple `structs` can be used by swapping `{ members }` for `( members )`, and enumerations by
68    changing `struct` to `enum`. The attributes, generic parameters, and where clause are optional
69    and can be omitted. The syntax for the generic parameters and bounds is almost the same as
70    normal; however, due to
71    [limitations](https://internals.rust-lang.org/t/allow-to-follow-path-fragments-in-declarative-macros/13676)
72    in macro parsing they do not support the `+` syntax for specifying multiple traits. Instead, you
73    should use `:`, so e.g. `T: Clone : Eq` means that `T` must implement both `Clone` and `Eq`.
74
75    The macro expands to two structures: `struct outer_name` wrapping a [`DropMoveWrapper`]
76    containing `struct inner_name`, which holds the actual members. All attributes in
77    `shared_attributes` are applied to both. Doc comments
78    [are also](https://stackoverflow.com/a/33999625/4071916) attributes, and can also be used here.
79    The inner visibility is applied to both the definition of the inner `struct` and the field of
80    the outer `struct` that wraps it, so if it is `pub` then anyone will be able to access it.
81
82    This macro also implements [`From`] to convert back and forth between the inner and outer
83    structures, and [`DropMoveTypes`] to tell [`DropMoveWrapper`] the relationship between the inner
84    and outer structures.
85
86    Note that this macro is implemented internally using a few others, which may appear in compiler
87    error messages. These all have names prefixed with `drop_move_wrap`.
88 */
89#[macro_export]
90macro_rules! drop_move_wrap {
91    {$($def:tt)+} => {
92        $crate::drop_move_wrap_match!{$($def)+}
93    };
94}
95
96#[doc(hidden)]
97#[macro_export]
98macro_rules! drop_move_wrap_match {
99    // struct/enum {}
100    {
101        $(#[$attrs:meta])*
102        $({$(#[$outer_only_attrs:meta])+})?
103        $vis:vis struct $name:ident $(<
104            $($lifetimes:lifetime $(: $lifetime_bounds1:lifetime $(+ $lifetime_bounds2:lifetime)*)?),*
105            $(,)?
106            $($types:ident $(:
107                $($lifetime_ty_bounds1:lifetime)? $($type_bounds1:path)?
108                $(: $($lifetime_ty_bounds2:lifetime)? $($type_bounds2:path)?)*
109            )?),*
110            $(,)?
111        >)?(
112            $(#[$inner_only_attrs:meta])*
113            $inner_vis:vis $inner_name:ident {$($members:tt)*}
114        ) $(where
115            $(
116                $($lifetime_wheres:lifetime)?
117                $($(for<($for_lt:lifetime),*>)? $type_wheres:ty)?
118                :
119                $($lifetime_ty_bounds3:lifetime)? $($type_bounds3:path)?
120                $(: $($lifetime_ty_bounds4:lifetime)? $($type_bounds4:path)?)*
121            ),*
122            $(,)?
123        )?;
124    } => {
125        $crate::drop_move_wrap_transcribe!{
126            { $(#[$attrs])* $($(#[$outer_only_attrs])+)? },
127            { $(#[$attrs])* $(#[$inner_only_attrs])* },
128            $vis, $inner_vis,
129            struct,
130            $name, $inner_name,
131            { $(<$($lifetimes, )*$($types, )*>)? },
132            { $(<
133                $($lifetimes $(: $lifetime_bounds1 $(+ $lifetime_bounds2)*)?, )*
134                $($types $(:
135                    $($type_bounds1)? $($lifetime_ty_bounds1)?
136                    $(+ $($type_bounds2)? $($lifetime_ty_bounds2)?)*
137                )?, )*
138            >)? },
139            { $(where
140                $(
141                    $($lifetime_wheres)?
142                    $($(for<($for_lt),*>)? $type_wheres)?
143                    :
144                    $($type_bounds3)? $($lifetime_ty_bounds3)?
145                    $(+ $($type_bounds4)? $($lifetime_ty_bounds4)?)*
146                ,)*
147            )? },
148            { $($members)* },
149        }
150    };
151
152    // struct ()
153    {
154        $(#[$attrs:meta])*
155        $({$(#[$outer_only_attrs:meta])+})?
156        $vis:vis struct $name:ident $(<
157            $($lifetimes:lifetime $(: $lifetime_bounds1:lifetime $(+ $lifetime_bounds2:lifetime)*)?),*
158            $(,)?
159            $($types:ident $(:
160                $($lifetime_ty_bounds1:lifetime)? $($type_bounds1:path)?
161                $(: $($lifetime_ty_bounds2:lifetime)? $($type_bounds2:path)?)*
162            )?),*
163            $(,)?
164        >)?(
165            $(#[$inner_only_attrs:meta])*
166            $inner_vis:vis $inner_name:ident ($($members:tt)*)
167        ) $(where
168            $(
169                $($lifetime_wheres:lifetime)?
170                $($(for<($for_lt:lifetime),*>)? $type_wheres:ty)?
171                :
172                $($lifetime_ty_bounds3:lifetime)? $($type_bounds3:path)?
173                $(: $($lifetime_ty_bounds4:lifetime)? $($type_bounds4:path)?)*
174            ),*
175            $(,)?
176        )?;
177    } => {
178        $crate::drop_move_wrap_transcribe!{
179            { $(#[$attrs])* $($(#[$outer_only_attrs])+)? },
180            { $(#[$attrs])* $(#[$inner_only_attrs])* },
181            $vis, $inner_vis,
182            tuple,
183            $name, $inner_name,
184            { $(<$($lifetimes, )*$($types, )*>)? },
185            { $(<
186                $($lifetimes $(: $lifetime_bounds1 $(+ $lifetime_bounds2)*)?, )*
187                $($types $(:
188                    $($type_bounds1)? $($lifetime_ty_bounds1)?
189                    $(+ $($type_bounds2)? $($lifetime_ty_bounds2)?)*
190                )?, )*
191            >)? },
192            { $(where
193                $(
194                    $($lifetime_wheres)?
195                    $($(for<($for_lt),*>)? $type_wheres)?
196                    :
197                    $($type_bounds3)? $($lifetime_ty_bounds3)?
198                    $(+ $($type_bounds4)? $($lifetime_ty_bounds4)?)*
199                ,)*
200            )? },
201            { $($members)* },
202        }
203    };
204
205    // enum
206    {
207        $(#[$attrs:meta])*
208        $({$(#[$outer_only_attrs:meta])+})?
209        $vis:vis enum $name:ident $(<
210            $($lifetimes:lifetime $(: $lifetime_bounds1:lifetime $(+ $lifetime_bounds2:lifetime)*)?),*
211            $(,)?
212            $($types:ident $(:
213                $($lifetime_ty_bounds1:lifetime)? $($type_bounds1:path)?
214                $(: $($lifetime_ty_bounds2:lifetime)? $($type_bounds2:path)?)*
215            )?),*
216            $(,)?
217        >)?(
218            $(#[$inner_only_attrs:meta])*
219            $inner_vis:vis $inner_name:ident {$($members:tt)*}
220        ) $(where
221            $(
222                $($lifetime_wheres:lifetime)?
223                $($(for<($for_lt:lifetime),*>)? $type_wheres:ty)?
224                :
225                $($lifetime_ty_bounds3:lifetime)? $($type_bounds3:path)?
226                $(: $($lifetime_ty_bounds4:lifetime)? $($type_bounds4:path)?)*
227            ),*
228            $(,)?
229        )?;
230    } => {
231        $crate::drop_move_wrap_transcribe!{
232            { $(#[$attrs])* $($(#[$outer_only_attrs])+)? },
233            { $(#[$attrs])* $(#[$inner_only_attrs])* },
234            $vis, $inner_vis,
235            enum,
236            $name, $inner_name,
237            { $(<$($lifetimes, )*$($types, )*>)? },
238            { $(<
239                $($lifetimes $(: $lifetime_bounds1 $(+ $lifetime_bounds2)*)?, )*
240                $($types $(:
241                    $($type_bounds1)? $($lifetime_ty_bounds1)?
242                    $(+ $($type_bounds2)? $($lifetime_ty_bounds2)?)*
243                )?, )*
244            >)? },
245            { $(where
246                $(
247                    $($lifetime_wheres)?
248                    $($(for<($for_lt),*>)? $type_wheres)?
249                    :
250                    $($type_bounds3)? $($lifetime_ty_bounds3)?
251                    $(+ $($type_bounds4)? $($lifetime_ty_bounds4)?)*
252                ,)*
253            )? },
254            { $($members)* },
255        }
256    };
257}
258
259#[doc(hidden)]
260#[macro_export]
261macro_rules! drop_move_wrap_transcribe {
262    {
263        { $($attrs:tt)* },
264        { $($inner_attrs:tt)* },
265        $vis:vis, $inner_vis:vis,
266        $decl_kind:ident,
267        $name:ident, $inner_name:ident,
268        { $($generic_params:tt)* },
269        { $($generic_bounds:tt)* },
270        { $($where_clause:tt)* },
271        { $($members:tt)* }$(,)?
272    } => {
273        $($attrs)*
274        $vis struct $name$($generic_bounds)*(
275            $inner_vis $crate::DropMoveWrapper<$inner_name$($generic_params)*>
276        ) $($where_clause)*;
277
278        $crate::drop_move_wrap_inner_decl!{
279            { $($inner_attrs)* },
280            $inner_vis, $decl_kind,
281            { $inner_name$($generic_bounds)* },
282            { $($where_clause)* },
283            { $($members)* },
284        }
285
286        impl$($generic_bounds)* From<$name$($generic_params)*> for $inner_name$($generic_params)*
287        $($where_clause)* {
288            fn from(x: $name$($generic_params)*) -> Self {
289                $crate::DropMoveWrapper::into_inner(x.0)
290            }
291        }
292
293        impl$($generic_bounds)* From<$inner_name$($generic_params)*> for $name$($generic_params)*
294        $($where_clause)* {
295            fn from(x: $inner_name$($generic_params)*) -> Self {
296                Self($crate::DropMoveWrapper::new(x))
297            }
298        }
299
300        impl$($generic_bounds)* $crate::DropMoveTypes for $inner_name$($generic_params)*
301        $($where_clause)* {
302            type Outer = $name$($generic_params)*;
303        }
304    };
305}
306
307#[doc(hidden)]
308#[macro_export]
309macro_rules! drop_move_wrap_inner_decl {
310    {
311        { $($inner_attrs:tt)* },
312        $inner_vis:vis, struct,
313        { $($inner_type:tt)* },
314        { $($where_clause:tt)* },
315        { $($members:tt)* },
316    } => {
317        $($inner_attrs)*
318        $inner_vis struct $($inner_type)* $($where_clause)* { $($members)* }
319    };
320
321    {
322        { $($inner_attrs:tt)* },
323        $inner_vis:vis, tuple,
324        { $($inner_type:tt)* },
325        { $($where_clause:tt)* },
326        { $($members:tt)* },
327    } => {
328        $($inner_attrs)*
329        $inner_vis struct $($inner_type)* ( $($members)* ) $($where_clause)*;
330    };
331
332    {
333        { $($inner_attrs:tt)* },
334        $inner_vis:vis, enum,
335        { $($inner_type:tt)* },
336        { $($where_clause:tt)* },
337        { $($members:tt)* },
338    } => {
339        $($inner_attrs)*
340        $inner_vis enum $($inner_type)* $($where_clause)* { $($members)* }
341    };
342}