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| if false { // <- toggle when debugging.
66            use ::std::hash::*;
67            let random = ::std::hash::RandomState::new().build_hasher().finish();
68            let temp_dir = &format!(
69                "{}/target/debug/macro-expansions",
70                ::std::env::var("CARGO_MANIFEST_DIR").unwrap()
71            );
72            ::std::fs::create_dir_all(temp_dir).ok();
73            let filename = &format!(
74                "{temp_dir}/drop_with_owned_fields-{random:#x}.rs",
75            );
76            ::std::fs::write(
77                filename,
78                ret.to_string(),
79            ).unwrap();
80            ::std::process::Command::new("rustfmt")
81                .args(["--edition", "2021", filename])
82                .status()
83                .ok();
84            quote!(
85                ::core::include!(#filename);
86            )
87        } else {
88            ret
89        })
90        .unwrap_or_else(|err| {
91            let mut errors =
92                err .into_iter()
93                    .map(|err| Error::new(
94                        err.span(),
95                        format_args!("`#[drop_with_owned_fields::drop_with_owned_fields]`: {}", err)
96                    ))
97            ;
98            let mut err = errors.next().unwrap();
99            errors.for_each(|cur| err.combine(cur));
100            err.to_compile_error()
101        })
102        .into()
103}
104
105enum Input {
106    DeriveInput(DeriveInput),
107    #[cfg(feature = "drop-sugar")]
108    ItemImpl(ItemImpl),
109}
110
111impl Parse for Input {
112    fn parse(input: ParseStream<'_>) -> Result<Self> {
113        let attrs = Attribute::parse_outer(input)?;
114        if input.peek(Token![impl]) {
115            #[cfg(not(feature = "drop-sugar"))] {
116                Err(input.error("\
117                    support for this kind of input requires enabling the `drop-sugar` Cargo \
118                    feature, like so:\n    \
119                    # Cargo.toml:\n\n    \
120                    [dependencies]\n    \
121                    # ...\n    \
122                    drop-with-owned-fields.version = \"x.y.z\"\n    \
123                    drop-with-owned-fields.features = [\"drop-sugar\"]\
124                "))
125            }
126            #[cfg(feature = "drop-sugar")]
127            {
128                let mut item_impl: ItemImpl = input.parse()?;
129                item_impl.attrs = attrs;
130                Ok(Self::ItemImpl(item_impl))
131            }
132        } else {
133            let mut derive_input: DeriveInput = input.parse()?;
134            derive_input.attrs = attrs;
135            Ok(Self::DeriveInput(derive_input))
136        }
137    }
138}
139
140fn drop_with_owned_fields_impl(
141    args: TokenStream2,
142    input: TokenStream2,
143) -> Result<TokenStream2>
144{
145    let input = match parse2(input)? {
146        Input::DeriveInput(it) => it,
147        #[cfg(feature = "drop-sugar")]
148        Input::ItemImpl(item_impl) => return drop_sugar::handle(args, item_impl),
149    };
150    let ref args: args::Args = parse2(args)?;
151    let DeriveInput {
152        vis: pub_,
153        attrs,
154        ident: StructName @ _,
155        generics,
156        data,
157    } = &input;
158    let ref docs =
159        attrs
160            .iter()
161            .filter(|attr| attr.path().is_ident("doc"))
162            .collect::<Vec<_>>()
163    ;
164    let DataStruct { fields, semi_token, .. } = match *data {
165        | Data::Struct(ref it) => it,
166        | Data::Enum(DataEnum { enum_token: token::Enum { span, .. }, .. })
167        | Data::Union(DataUnion { union_token: token::Union { span, .. }, .. })
168        => {
169            return Err(Error::new(span, "expected a `struct`"));
170        },
171    };
172    fn super_of(pub_: &Visibility) -> Cow<'_, Visibility> {
173        match &*pub_ {
174            | Visibility::Public(_) => pub_.borrowed(),
175            | Visibility::Inherited => Cow::Owned(parse_quote!(pub(super))),
176            | Visibility::Restricted(VisRestricted { path, .. }) => {
177                match path.get_ident().map(ToString::to_string).as_deref() {
178                    | Some("crate") => pub_.borrowed(),
179                    | _ if path.leading_colon.is_some() => pub_.borrowed(),
180                    | Some("self") => Cow::Owned(parse_quote!(
181                        pub(super)
182                    )),
183                    | _ => Cow::Owned(parse_quote!(
184                        pub(in super :: #path)
185                    )),
186                }
187            },
188        }
189    }
190    let pub_super = super_of(pub_);
191    let fields = fields.clone().also(|fields| {
192        fields.iter_mut().for_each(|Field { vis: pub_, .. }| {
193            *pub_ = super_of(pub_).into_owned();
194        });
195    });
196
197    let pub_capped_at_crate = match &*pub_super {
198        | Visibility::Public(_) => Cow::Owned(parse_quote!(
199            pub(crate)
200        )),
201        | it => it.borrowed(),
202    };
203    let (IntroGenerics @ _, FwdGenerics @ _, where_clauses) = generics.split_for_impl();
204
205    let struct_name_helper_module = &format_ident!(
206        "_{StructName}ඞdrop_with_owned_fields"
207    );
208
209    let fields_struct_span;
210    let mut maybe_re_export = quote!();
211    let StructNameFields @ _ = match &args.maybe_rename {
212        Either::Left(RenameOfDestructuredFieldsType {
213            pub_,
214            struct_,
215            name: StructNameFields @ _,
216        }) => {
217            maybe_re_export = quote!(
218                #pub_ use #struct_name_helper_module::#StructNameFields;
219            );
220            fields_struct_span = struct_.span();
221            StructNameFields
222        },
223        Either::Right(infer) => {
224            fields_struct_span = infer.span_location();
225            &format_ident!("{StructName}ඞFields", span=fields_struct_span)
226        },
227    };
228    let struct_fields_def = quote_spanned!(fields_struct_span=>
229        #(#attrs)*
230        #pub_super
231        struct #StructNameFields #IntroGenerics
232        #where_clauses
233        #fields
234        #semi_token
235    );
236
237    let other_derives_and_attrs_hack =
238        derives::best_effort_compat_with_other_derives_and_attrs(
239            &input,
240            &quote!(#struct_name_helper_module :: #StructNameFields),
241        )?
242    ;
243
244    Ok(quote!(
245        // we keep this outside the module to make sure no evil derive tries to mess with our
246        // private field.
247        #other_derives_and_attrs_hack
248
249        #[doc(inline)]
250        #(#docs)*
251        #pub_ use #struct_name_helper_module::#StructName;
252
253        #maybe_re_export
254
255        mod #struct_name_helper_module {
256            #![allow(nonstandard_style)]
257
258            #[allow(unused)]
259            use super::*;
260
261            #struct_fields_def
262
263            #[repr(transparent)]
264            #pub_super
265            struct #StructName #IntroGenerics
266            #where_clauses
267            {
268                ඞmanually_drop_fields:
269                    ::core::mem::ManuallyDrop<
270                        ::drop_with_owned_fields::DestructuredFieldsOf<Self>,
271                    >
272                ,
273            }
274
275            impl #IntroGenerics
276                ::core::ops::Drop
277            for
278                #StructName #FwdGenerics
279            {
280                #[inline]
281                fn drop(&mut self) {
282                    <Self as ::drop_with_owned_fields::DropWithOwnedFields>::drop(
283                        unsafe {
284                            ::core::mem::ManuallyDrop::take(&mut self.ඞmanually_drop_fields)
285                        }
286                    )
287                }
288            }
289
290            impl #IntroGenerics
291                ::drop_with_owned_fields::ඞ::drop_with_owned_fields_annotation
292            for
293                #StructName #FwdGenerics
294            #where_clauses
295            {}
296
297            impl #IntroGenerics
298                ::drop_with_owned_fields::DestructureFields
299            for
300                #StructName #FwdGenerics
301            #where_clauses
302            {
303                type Fields = #StructNameFields #FwdGenerics;
304            }
305
306            impl #IntroGenerics
307                ::core::convert::From<
308                    #StructNameFields #FwdGenerics,
309                >
310            for
311                #StructName #FwdGenerics
312            #where_clauses
313            {
314                #[inline]
315                fn from(this: #StructNameFields #FwdGenerics)
316                  -> Self
317                {
318                    this.into()
319                }
320            }
321
322            impl #IntroGenerics #StructNameFields #FwdGenerics
323            #where_clauses
324            {
325                #[inline]
326                #pub_
327                const
328                fn into(self) -> #StructName #FwdGenerics {
329                    #StructName {
330                        ඞmanually_drop_fields: ::core::mem::ManuallyDrop::new(
331                            self,
332                        ),
333                    }
334                }
335            }
336
337            impl #IntroGenerics #StructName #FwdGenerics {
338                #[allow(unused)]
339                #[inline]
340                #pub_capped_at_crate
341                const
342                fn destructure_fields_disabling_impl_drop(self: #StructName #FwdGenerics)
343                  -> #StructNameFields #FwdGenerics
344                {
345                    // Defuse extra `Drop` glue of `Self`.
346                    let this = ::core::mem::ManuallyDrop::new(self);
347                    unsafe {
348                        /* not `const`:
349                        ::core::mem::ManuallyDrop::take(
350                            &mut this.ඞmanually_drop_fields,
351                        )
352                        // not available before `1.83.0`
353                        ::core::mem::transmute_copy(&this)
354                        // */
355                        ::core::mem::ManuallyDrop::into_inner(
356                            ::drop_with_owned_fields::ඞ::ConstTransmuteUnchecked::<
357                                #StructName #FwdGenerics,
358                                #StructNameFields #FwdGenerics,
359                            >
360                            {
361                                src: this,
362                            }
363                            .dst
364                        )
365                    }
366                }
367            }
368
369            impl #IntroGenerics
370                ::core::ops::Deref
371            for
372                #StructName #FwdGenerics
373            #where_clauses
374            {
375                type Target = ::drop_with_owned_fields::DestructuredFieldsOf<Self>;
376
377                #[inline]
378                fn deref(&self) -> &Self::Target {
379                    &*self.ඞmanually_drop_fields
380                }
381            }
382            impl #IntroGenerics
383                ::core::ops::DerefMut
384            for
385                #StructName #FwdGenerics
386            #where_clauses
387            {
388                #[inline]
389                fn deref_mut(&mut self) -> &mut Self::Target {
390                    &mut *self.ඞmanually_drop_fields
391                }
392            }
393        }
394    ))
395}