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