drop_with_owned_fields_proc_macros/
_mod.rs

1//! Crate not intended for direct use.
2//! Use https:://docs.rs/drop-with-owned-fields instead.
3// Templated by `cargo-generate` using https://github.com/danielhenrymantilla/proc-macro-template
4#![allow(nonstandard_style, unused_imports, unused_braces)]
5
6use ::core::{
7    mem,
8    ops::Not as _,
9};
10use std::borrow::Cow;
11use ::proc_macro::{
12    TokenStream,
13};
14use ::proc_macro2::{
15    Span,
16    TokenStream as TokenStream2,
17    TokenTree as TT,
18};
19use quote::quote_spanned;
20use ::quote::{
21    format_ident,
22    ToTokens,
23};
24use ::syn::{*,
25    parse::{Parse, Parser, ParseStream},
26    punctuated::Punctuated,
27    Result, // Explicitly shadow it
28    spanned::Spanned,
29};
30use self::utils::default_to_mixed_site_span::{
31    quote, parse_quote, SpanLocationExt as _,
32};
33
34#[macro_use]
35#[path = "utils/_mod.rs"]
36mod utils;
37use utils::{BorrowedExt, Retain};
38
39mod args;
40
41mod derives;
42
43#[cfg(feature = "drop-sugar")]
44mod drop_sugar;
45
46#[proc_macro_attribute] /** Not part of the public API */ pub
47fn ඞannihilate(
48    _: TokenStream,
49    _: TokenStream,
50) -> TokenStream {
51    TokenStream::new()
52}
53
54///
55#[proc_macro_attribute] pub
56fn drop_with_owned_fields(
57    args: TokenStream,
58    input: TokenStream,
59) -> TokenStream
60{
61    drop_with_owned_fields_impl(args.into(), input.into())
62    //  .map(|ret| { println!("{}", ret); ret })
63        .unwrap_or_else(|err| {
64            let mut errors =
65                err .into_iter()
66                    .map(|err| Error::new(
67                        err.span(),
68                        format_args!("`#[drop_with_owned_fields::drop_with_owned_fields]`: {}", err),
69                    ))
70            ;
71            let mut err = errors.next().unwrap();
72            errors.for_each(|cur| err.combine(cur));
73            err.to_compile_error()
74        })
75        .into()
76}
77
78enum Input {
79    DeriveInput(DeriveInput),
80    #[cfg(feature = "drop-sugar")]
81    ItemImpl(ItemImpl),
82}
83
84impl Parse for Input {
85    fn parse(input: ParseStream<'_>) -> Result<Self> {
86        let attrs = Attribute::parse_outer(input)?;
87        if input.peek(Token![impl]) {
88            #[cfg(not(feature = "drop-sugar"))] {
89                Err(input.error("\
90                    support for this kind of input requires enabling the `drop-sugar` Cargo \
91                    feature, like so:\n    \
92                    # Cargo.toml:\n\n    \
93                    [dependencies]\n    \
94                    # ...\n    \
95                    drop-with-owned-fields.version = \"x.y.z\"\n    \
96                    drop-with-owned-fields.features = [\"drop-sugar\"]\
97                "))
98            }
99            #[cfg(feature = "drop-sugar")]
100            {
101                let mut item_impl: ItemImpl = input.parse()?;
102                item_impl.attrs = attrs;
103                Ok(Self::ItemImpl(item_impl))
104            }
105        } else {
106            let mut derive_input: DeriveInput = input.parse()?;
107            derive_input.attrs = attrs;
108            Ok(Self::DeriveInput(derive_input))
109        }
110    }
111}
112
113fn drop_with_owned_fields_impl(
114    args: TokenStream2,
115    input: TokenStream2,
116) -> Result<TokenStream2>
117{
118    let input = match parse2(input)? {
119        Input::DeriveInput(it) => it,
120        #[cfg(feature = "drop-sugar")]
121        Input::ItemImpl(item_impl) => return drop_sugar::handle(args, item_impl),
122    };
123    let args: args::Args = parse2(args)?;
124    let DeriveInput {
125        vis: pub_,
126        attrs,
127        ident: StructName @ _,
128        generics,
129        data,
130    } = &input;
131    let ref docs =
132        attrs
133            .iter()
134            .filter(|attr| attr.path().is_ident("doc"))
135            .collect::<Vec<_>>()
136    ;
137    let DataStruct { fields, semi_token, .. } = match *data {
138        | Data::Struct(ref it) => it,
139        | Data::Enum(DataEnum { enum_token: token::Enum { span, .. }, .. })
140        | Data::Union(DataUnion { union_token: token::Union { span, .. }, .. })
141        => {
142            return Err(Error::new(span, "expected a `struct`"));
143        },
144    };
145    let pub_super = match &*pub_ {
146        | Visibility::Public(_) => pub_.borrowed(),
147        | Visibility::Inherited => Cow::Owned(parse_quote!(pub(super))),
148        | Visibility::Restricted(VisRestricted { path, .. }) => {
149            match path.get_ident().map(ToString::to_string).as_deref() {
150                | Some("crate")
151                | _ if path.leading_colon.is_some()
152                => {
153                    pub_.borrowed()
154                },
155                | Some("self") => Cow::Owned(parse_quote!(
156                    pub(super)
157                )),
158                | _ => Cow::Owned(parse_quote!(
159                    pub(in super :: #path)
160                )),
161            }
162        },
163    };
164    let pub_capped_at_crate = match &*pub_ {
165        | Visibility::Public(_) => Cow::Owned(parse_quote!(
166            pub(crate)
167        )),
168        | _ => pub_.borrowed(),
169    };
170    let (IntroGenerics @ _, FwdGenerics @ _, where_clauses) = generics.split_for_impl();
171
172    let fields_struct_pub;
173    let fields_struct_span;
174    let mut maybe_doc_hidden = quote!();
175    let StructNameDestructuredFields @ _ = if let Some(rename) = &args.maybe_rename {
176        fields_struct_pub = &rename.pub_;
177        fields_struct_span = rename.type_.span();
178        &rename.name
179    } else {
180        maybe_doc_hidden = quote!(#[doc(hidden)]);
181        fields_struct_pub = pub_;
182        fields_struct_span = Span::mixed_site();
183        &format_ident!("{StructName}ඞDestructuredFields")
184    };
185    let struct_fields_def = quote_spanned!(fields_struct_span=>
186        #maybe_doc_hidden
187        #(#attrs)*
188        #fields_struct_pub
189        struct #StructNameDestructuredFields #IntroGenerics
190        #where_clauses
191        #fields
192        #semi_token
193    );
194
195    let struct_name_helper_module = &format_ident!(
196        "_{StructName}ඞdrop_with_owned_fields"
197    );
198
199    let other_derives_and_attrs_hack =
200        derives::best_effort_compat_with_other_derives_and_attrs(
201            &input,
202            StructNameDestructuredFields,
203        )?
204    ;
205
206    Ok(quote!(
207        #other_derives_and_attrs_hack
208
209        #struct_fields_def
210
211        #[doc(inline)]
212        #(#docs)*
213        #pub_ use #struct_name_helper_module::#StructName;
214
215        mod #struct_name_helper_module {
216            use super::*;
217
218            #[repr(transparent)]
219            #pub_super
220            struct #StructName #IntroGenerics
221            #where_clauses
222            {
223                manually_drop_fields:
224                    ::core::mem::ManuallyDrop<
225                        ::drop_with_owned_fields::DestructuredFieldsOf<Self>,
226                    >
227                ,
228            }
229
230            impl #IntroGenerics
231                ::core::ops::Drop
232            for
233                #StructName #FwdGenerics
234            {
235                #[inline]
236                fn drop(&mut self) {
237                    <Self as ::drop_with_owned_fields::DropWithOwnedFields>::drop(
238                        unsafe {
239                            ::core::mem::ManuallyDrop::take(&mut self.manually_drop_fields)
240                        }
241                    )
242                }
243            }
244
245            impl #IntroGenerics
246                ::drop_with_owned_fields::ඞ::drop_with_owned_fields_annotation
247            for
248                #StructName #FwdGenerics
249            #where_clauses
250            {}
251
252            impl #IntroGenerics
253                ::drop_with_owned_fields::DestructureFields
254            for
255                #StructName #FwdGenerics
256            #where_clauses
257            {
258                type DestructuredFields = #StructNameDestructuredFields #FwdGenerics;
259
260                #[inline]
261                fn destructure_fields_disabling_extra_drop(self)
262                  -> Self::DestructuredFields
263                {
264                    #![deny(unconditional_recursion)]
265                    Self::destructure_fields_disabling_extra_drop(self)
266                }
267            }
268
269            impl #IntroGenerics
270                ::core::convert::From<
271                    #StructNameDestructuredFields #FwdGenerics,
272                >
273            for
274                #StructName #FwdGenerics
275            #where_clauses
276            {
277                #[inline]
278                fn from(this: #StructNameDestructuredFields #FwdGenerics)
279                  -> Self
280                {
281                    this.into()
282                }
283            }
284
285            impl #IntroGenerics #StructNameDestructuredFields #FwdGenerics
286            #where_clauses
287            {
288                #[inline]
289                #pub_
290                const
291                fn into(self) -> #StructName #FwdGenerics {
292                    #StructName {
293                        manually_drop_fields: ::core::mem::ManuallyDrop::new(
294                            self,
295                        ),
296                    }
297                }
298            }
299
300            impl #IntroGenerics #StructName #FwdGenerics {
301                #[inline]
302                #pub_capped_at_crate
303                const
304                fn destructure_fields_disabling_extra_drop(self: #StructName #FwdGenerics)
305                  -> #StructNameDestructuredFields #FwdGenerics
306                {
307                    // Defuse extra `Drop` glue of `Self`.
308                    let this = ::core::mem::ManuallyDrop::new(self);
309                    unsafe {
310                        /* not `const`:
311                        ::core::mem::ManuallyDrop::take(
312                            &mut this.manually_drop_fields,
313                        )
314                        // not available before `1.83.0`
315                        ::core::mem::transmute_copy(&this)
316                        // */
317                        ::core::mem::ManuallyDrop::into_inner(
318                            ::drop_with_owned_fields::ඞ::ConstTransmuteUnchecked::<
319                                #StructName #FwdGenerics,
320                                #StructNameDestructuredFields #FwdGenerics,
321                            >
322                            {
323                                src: this,
324                            }
325                            .dst
326                        )
327                    }
328                }
329            }
330
331            // if no `deref=false`
332            impl #IntroGenerics
333                ::core::ops::Deref
334            for
335                #StructName #FwdGenerics
336            #where_clauses
337            {
338                type Target = ::drop_with_owned_fields::DestructuredFieldsOf<Self>;
339
340                #[inline]
341                fn deref(&self) -> &Self::Target {
342                    &*self.manually_drop_fields
343                }
344            }
345            impl #IntroGenerics
346                ::core::ops::DerefMut
347            for
348                #StructName #FwdGenerics
349            #where_clauses
350            {
351                #[inline]
352                fn deref_mut(&mut self) -> &mut Self::Target {
353                    &mut *self.manually_drop_fields
354                }
355            }
356        }
357    ))
358}