derive_more/
utils.rs

1#![cfg_attr(not(feature = "default"), allow(dead_code), allow(unused_mut))]
2
3use crate::syn_compat::{AttributeExt as _, NestedMeta, ParsedMeta};
4use proc_macro2::{Span, TokenStream};
5use quote::{quote, ToTokens};
6use syn::{
7    parse_quote, punctuated::Punctuated, spanned::Spanned, Attribute, Data,
8    DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, GenericParam,
9    Generics, Ident, ImplGenerics, Index, Result, Token, Type, TypeGenerics,
10    TypeParamBound, Variant, WhereClause,
11};
12
13#[derive(Clone, Copy, Default)]
14pub struct DeterministicState;
15
16impl std::hash::BuildHasher for DeterministicState {
17    type Hasher = std::collections::hash_map::DefaultHasher;
18
19    fn build_hasher(&self) -> Self::Hasher {
20        Self::Hasher::default()
21    }
22}
23
24pub type HashMap<K, V> = std::collections::HashMap<K, V, DeterministicState>;
25pub type HashSet<K> = std::collections::HashSet<K, DeterministicState>;
26
27#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
28pub enum RefType {
29    No,
30    Ref,
31    Mut,
32}
33
34impl RefType {
35    pub fn lifetime(self) -> TokenStream {
36        match self {
37            RefType::No => quote!(),
38            _ => quote!('__deriveMoreLifetime),
39        }
40    }
41
42    pub fn reference(self) -> TokenStream {
43        match self {
44            RefType::No => quote!(),
45            RefType::Ref => quote!(&),
46            RefType::Mut => quote!(&mut),
47        }
48    }
49
50    pub fn mutability(self) -> TokenStream {
51        match self {
52            RefType::Mut => quote!(mut),
53            _ => quote!(),
54        }
55    }
56
57    pub fn pattern_ref(self) -> TokenStream {
58        match self {
59            RefType::Ref => quote!(ref),
60            RefType::Mut => quote!(ref mut),
61            RefType::No => quote!(),
62        }
63    }
64
65    pub fn reference_with_lifetime(self) -> TokenStream {
66        if !self.is_ref() {
67            return quote!();
68        }
69        let lifetime = self.lifetime();
70        let mutability = self.mutability();
71        quote!(&#lifetime #mutability)
72    }
73
74    pub fn is_ref(self) -> bool {
75        match self {
76            RefType::No => false,
77            _ => true,
78        }
79    }
80
81    pub fn from_attr_name(name: &str) -> Self {
82        match name {
83            "owned" => RefType::No,
84            "ref" => RefType::Ref,
85            "ref_mut" => RefType::Mut,
86            _ => panic!("'{}' is not a RefType", name),
87        }
88    }
89}
90
91pub fn numbered_vars(count: usize, prefix: &str) -> Vec<Ident> {
92    (0..count)
93        .map(|i| Ident::new(&format!("__{}{}", prefix, i), Span::call_site()))
94        .collect()
95}
96
97pub fn field_idents<'a>(fields: &'a [&'a Field]) -> Vec<&'a Ident> {
98    fields
99        .iter()
100        .map(|f| {
101            f.ident
102                .as_ref()
103                .expect("Tried to get field names of a tuple struct")
104        })
105        .collect()
106}
107
108pub fn get_field_types_iter<'a>(
109    fields: &'a [&'a Field],
110) -> Box<dyn Iterator<Item = &'a Type> + 'a> {
111    Box::new(fields.iter().map(|f| &f.ty))
112}
113
114pub fn get_field_types<'a>(fields: &'a [&'a Field]) -> Vec<&'a Type> {
115    get_field_types_iter(fields).collect()
116}
117
118pub fn add_extra_type_param_bound_op_output<'a>(
119    generics: &'a Generics,
120    trait_ident: &'a Ident,
121) -> Generics {
122    let mut generics = generics.clone();
123    for type_param in &mut generics.type_params_mut() {
124        let type_ident = &type_param.ident;
125        let bound: TypeParamBound = parse_quote! {
126            ::core::ops::#trait_ident<Output=#type_ident>
127        };
128        type_param.bounds.push(bound)
129    }
130
131    generics
132}
133
134pub fn add_extra_ty_param_bound_op<'a>(
135    generics: &'a Generics,
136    trait_ident: &'a Ident,
137) -> Generics {
138    add_extra_ty_param_bound(generics, &quote!(::core::ops::#trait_ident))
139}
140
141pub fn add_extra_ty_param_bound<'a>(
142    generics: &'a Generics,
143    bound: &'a TokenStream,
144) -> Generics {
145    let mut generics = generics.clone();
146    let bound: TypeParamBound = parse_quote! { #bound };
147    for type_param in &mut generics.type_params_mut() {
148        type_param.bounds.push(bound.clone())
149    }
150
151    generics
152}
153
154pub fn add_extra_ty_param_bound_ref<'a>(
155    generics: &'a Generics,
156    bound: &'a TokenStream,
157    ref_type: RefType,
158) -> Generics {
159    match ref_type {
160        RefType::No => add_extra_ty_param_bound(generics, bound),
161        _ => {
162            let generics = generics.clone();
163            let idents = generics.type_params().map(|x| &x.ident);
164            let ref_with_lifetime = ref_type.reference_with_lifetime();
165            add_extra_where_clauses(
166                &generics,
167                quote!(
168                    where #(#ref_with_lifetime #idents: #bound),*
169                ),
170            )
171        }
172    }
173}
174
175pub fn add_extra_generic_param(
176    generics: &Generics,
177    generic_param: TokenStream,
178) -> Generics {
179    let generic_param: GenericParam = parse_quote! { #generic_param };
180    let mut generics = generics.clone();
181    generics.params.push(generic_param);
182
183    generics
184}
185
186pub fn add_extra_generic_type_param(
187    generics: &Generics,
188    generic_param: TokenStream,
189) -> Generics {
190    let generic_param: GenericParam = parse_quote! { #generic_param };
191    let lifetimes: Vec<GenericParam> =
192        generics.lifetimes().map(|x| x.clone().into()).collect();
193    let type_params: Vec<GenericParam> =
194        generics.type_params().map(|x| x.clone().into()).collect();
195    let const_params: Vec<GenericParam> =
196        generics.const_params().map(|x| x.clone().into()).collect();
197    let mut generics = generics.clone();
198    generics.params = Default::default();
199    generics.params.extend(lifetimes);
200    generics.params.extend(type_params);
201    generics.params.push(generic_param);
202    generics.params.extend(const_params);
203
204    generics
205}
206
207pub fn add_extra_where_clauses(
208    generics: &Generics,
209    type_where_clauses: TokenStream,
210) -> Generics {
211    let mut type_where_clauses: WhereClause = parse_quote! { #type_where_clauses };
212    let mut new_generics = generics.clone();
213    if let Some(old_where) = new_generics.where_clause {
214        type_where_clauses.predicates.extend(old_where.predicates)
215    }
216    new_generics.where_clause = Some(type_where_clauses);
217
218    new_generics
219}
220
221pub fn add_where_clauses_for_new_ident<'a>(
222    generics: &'a Generics,
223    fields: &[&'a Field],
224    type_ident: &Ident,
225    type_where_clauses: TokenStream,
226    sized: bool,
227) -> Generics {
228    let generic_param = if fields.len() > 1 {
229        quote!(#type_ident: ::core::marker::Copy)
230    } else if sized {
231        quote!(#type_ident)
232    } else {
233        quote!(#type_ident: ?::core::marker::Sized)
234    };
235
236    let generics = add_extra_where_clauses(generics, type_where_clauses);
237    add_extra_generic_type_param(&generics, generic_param)
238}
239
240pub fn unnamed_to_vec(fields: &FieldsUnnamed) -> Vec<&Field> {
241    fields.unnamed.iter().collect()
242}
243
244pub fn named_to_vec(fields: &FieldsNamed) -> Vec<&Field> {
245    fields.named.iter().collect()
246}
247
248fn panic_one_field(trait_name: &str, trait_attr: &str) -> ! {
249    panic!(
250        "derive({}) only works when forwarding to a single field. Try putting #[{}] or #[{}(ignore)] on the fields in the struct",
251        trait_name, trait_attr, trait_attr,
252    )
253}
254
255#[derive(Copy, Clone, Debug, PartialEq, Eq)]
256pub enum DeriveType {
257    Unnamed,
258    Named,
259    Enum,
260}
261
262pub struct State<'input> {
263    pub input: &'input DeriveInput,
264    pub trait_name: &'static str,
265    pub method_ident: Ident,
266    pub trait_module: TokenStream,
267    pub trait_path: TokenStream,
268    pub trait_path_params: Vec<TokenStream>,
269    pub trait_attr: String,
270    pub derive_type: DeriveType,
271    pub fields: Vec<&'input Field>,
272    pub variants: Vec<&'input Variant>,
273    pub variant_states: Vec<State<'input>>,
274    pub variant: Option<&'input Variant>,
275    pub generics: Generics,
276    pub default_info: FullMetaInfo,
277    full_meta_infos: Vec<FullMetaInfo>,
278}
279
280#[derive(Default, Clone)]
281pub struct AttrParams {
282    pub enum_: Vec<&'static str>,
283    pub variant: Vec<&'static str>,
284    pub struct_: Vec<&'static str>,
285    pub field: Vec<&'static str>,
286}
287
288impl AttrParams {
289    pub fn new(params: Vec<&'static str>) -> AttrParams {
290        AttrParams {
291            enum_: params.clone(),
292            struct_: params.clone(),
293            variant: params.clone(),
294            field: params,
295        }
296    }
297    pub fn struct_(params: Vec<&'static str>) -> AttrParams {
298        AttrParams {
299            enum_: vec![],
300            struct_: params,
301            variant: vec![],
302            field: vec![],
303        }
304    }
305
306    pub fn ignore_and_forward() -> AttrParams {
307        AttrParams::new(vec!["ignore", "forward"])
308    }
309}
310
311impl<'input> State<'input> {
312    pub fn new<'arg_input>(
313        input: &'arg_input DeriveInput,
314        trait_name: &'static str,
315        trait_module: TokenStream,
316        trait_attr: String,
317    ) -> Result<State<'arg_input>> {
318        State::new_impl(
319            input,
320            trait_name,
321            trait_module,
322            trait_attr,
323            AttrParams::default(),
324            true,
325        )
326    }
327
328    pub fn with_field_ignore<'arg_input>(
329        input: &'arg_input DeriveInput,
330        trait_name: &'static str,
331        trait_module: TokenStream,
332        trait_attr: String,
333    ) -> Result<State<'arg_input>> {
334        State::new_impl(
335            input,
336            trait_name,
337            trait_module,
338            trait_attr,
339            AttrParams::new(vec!["ignore"]),
340            true,
341        )
342    }
343
344    pub fn with_field_ignore_and_forward<'arg_input>(
345        input: &'arg_input DeriveInput,
346        trait_name: &'static str,
347        trait_module: TokenStream,
348        trait_attr: String,
349    ) -> Result<State<'arg_input>> {
350        State::new_impl(
351            input,
352            trait_name,
353            trait_module,
354            trait_attr,
355            AttrParams::new(vec!["ignore", "forward"]),
356            true,
357        )
358    }
359
360    pub fn with_field_ignore_and_refs<'arg_input>(
361        input: &'arg_input DeriveInput,
362        trait_name: &'static str,
363        trait_module: TokenStream,
364        trait_attr: String,
365    ) -> Result<State<'arg_input>> {
366        State::new_impl(
367            input,
368            trait_name,
369            trait_module,
370            trait_attr,
371            AttrParams::new(vec!["ignore", "owned", "ref", "ref_mut"]),
372            true,
373        )
374    }
375
376    pub fn with_attr_params<'arg_input>(
377        input: &'arg_input DeriveInput,
378        trait_name: &'static str,
379        trait_module: TokenStream,
380        trait_attr: String,
381        allowed_attr_params: AttrParams,
382    ) -> Result<State<'arg_input>> {
383        State::new_impl(
384            input,
385            trait_name,
386            trait_module,
387            trait_attr,
388            allowed_attr_params,
389            true,
390        )
391    }
392
393    pub fn with_type_bound<'arg_input>(
394        input: &'arg_input DeriveInput,
395        trait_name: &'static str,
396        trait_module: TokenStream,
397        trait_attr: String,
398        allowed_attr_params: AttrParams,
399        add_type_bound: bool,
400    ) -> Result<State<'arg_input>> {
401        Self::new_impl(
402            input,
403            trait_name,
404            trait_module,
405            trait_attr,
406            allowed_attr_params,
407            add_type_bound,
408        )
409    }
410
411    fn new_impl<'arg_input>(
412        input: &'arg_input DeriveInput,
413        trait_name: &'static str,
414        trait_module: TokenStream,
415        trait_attr: String,
416        allowed_attr_params: AttrParams,
417        add_type_bound: bool,
418    ) -> Result<State<'arg_input>> {
419        let trait_name = trait_name.trim_end_matches("ToInner");
420        let trait_ident = Ident::new(trait_name, Span::call_site());
421        let method_ident = Ident::new(&trait_attr, Span::call_site());
422        let trait_path = quote!(#trait_module::#trait_ident);
423        let (derive_type, fields, variants): (_, Vec<_>, Vec<_>) = match input.data {
424            Data::Struct(ref data_struct) => match data_struct.fields {
425                Fields::Unnamed(ref fields) => {
426                    (DeriveType::Unnamed, unnamed_to_vec(fields), vec![])
427                }
428
429                Fields::Named(ref fields) => {
430                    (DeriveType::Named, named_to_vec(fields), vec![])
431                }
432                Fields::Unit => (DeriveType::Named, vec![], vec![]),
433            },
434            Data::Enum(ref data_enum) => (
435                DeriveType::Enum,
436                vec![],
437                data_enum.variants.iter().collect(),
438            ),
439            Data::Union(_) => {
440                panic!("cannot derive({}) for union", trait_name)
441            }
442        };
443        let attrs: Vec<_> = if derive_type == DeriveType::Enum {
444            variants.iter().map(|v| &v.attrs).collect()
445        } else {
446            fields.iter().map(|f| &f.attrs).collect()
447        };
448
449        let (allowed_attr_params_outer, allowed_attr_params_inner) =
450            if derive_type == DeriveType::Enum {
451                (&allowed_attr_params.enum_, &allowed_attr_params.variant)
452            } else {
453                (&allowed_attr_params.struct_, &allowed_attr_params.field)
454            };
455
456        let struct_meta_info =
457            get_meta_info(&trait_attr, &input.attrs, allowed_attr_params_outer)?;
458        let meta_infos: Result<Vec<_>> = attrs
459            .iter()
460            .map(|attrs| get_meta_info(&trait_attr, attrs, allowed_attr_params_inner))
461            .collect();
462        let meta_infos = meta_infos?;
463        let first_match = meta_infos
464            .iter()
465            .filter_map(|info| info.enabled.map(|_| info))
466            .next();
467
468        // Default to enabled true, except when first attribute has explicit
469        // enabling.
470        //
471        // Except for derive Error.
472        //
473        // The way `else` case works is that if any field have any valid
474        // attribute specified, then all fields without any attributes
475        // specified are filtered out from `State::enabled_fields`.
476        //
477        // However, derive Error *infers* fields and there are cases when
478        // one of the fields may have an attribute specified, but another field
479        // would be inferred. So, for derive Error macro we default enabled
480        // to true unconditionally (i.e., even if some fields have attributes
481        // specified).
482        let default_enabled = if trait_name == "Error" {
483            true
484        } else {
485            first_match.map_or(true, |info| !info.enabled.unwrap())
486        };
487
488        let defaults = struct_meta_info.into_full(FullMetaInfo {
489            enabled: default_enabled,
490            forward: false,
491            // Default to owned true, except when first attribute has one of owned,
492            // ref or ref_mut
493            // - not a single attribute means default true
494            // - an attribute, but non of owned, ref or ref_mut means default true
495            // - an attribute, and owned, ref or ref_mut means default false
496            owned: first_match.map_or(true, |info| {
497                info.owned.is_none() && info.ref_.is_none() || info.ref_mut.is_none()
498            }),
499            ref_: false,
500            ref_mut: false,
501            info: MetaInfo::default(),
502        });
503
504        let full_meta_infos: Vec<_> = meta_infos
505            .into_iter()
506            .map(|info| info.into_full(defaults.clone()))
507            .collect();
508
509        let variant_states: Result<Vec<_>> = if derive_type == DeriveType::Enum {
510            variants
511                .iter()
512                .zip(full_meta_infos.iter().cloned())
513                .map(|(variant, info)| {
514                    State::from_variant(
515                        input,
516                        trait_name,
517                        trait_module.clone(),
518                        trait_attr.clone(),
519                        allowed_attr_params.clone(),
520                        variant,
521                        info,
522                    )
523                })
524                .collect()
525        } else {
526            Ok(vec![])
527        };
528
529        let generics = if add_type_bound {
530            add_extra_ty_param_bound(&input.generics, &trait_path)
531        } else {
532            input.generics.clone()
533        };
534
535        Ok(State {
536            input,
537            trait_name,
538            method_ident,
539            trait_module,
540            trait_path,
541            trait_path_params: vec![],
542            trait_attr,
543            // input,
544            fields,
545            variants,
546            variant_states: variant_states?,
547            variant: None,
548            derive_type,
549            generics,
550            full_meta_infos,
551            default_info: defaults,
552        })
553    }
554
555    pub fn from_variant<'arg_input>(
556        input: &'arg_input DeriveInput,
557        trait_name: &'static str,
558        trait_module: TokenStream,
559        trait_attr: String,
560        allowed_attr_params: AttrParams,
561        variant: &'arg_input Variant,
562        default_info: FullMetaInfo,
563    ) -> Result<State<'arg_input>> {
564        let trait_name = trait_name.trim_end_matches("ToInner");
565        let trait_ident = Ident::new(trait_name, Span::call_site());
566        let method_ident = Ident::new(&trait_attr, Span::call_site());
567        let trait_path = quote!(#trait_module::#trait_ident);
568        let (derive_type, fields): (_, Vec<_>) = match variant.fields {
569            Fields::Unnamed(ref fields) => {
570                (DeriveType::Unnamed, unnamed_to_vec(fields))
571            }
572
573            Fields::Named(ref fields) => (DeriveType::Named, named_to_vec(fields)),
574            Fields::Unit => (DeriveType::Named, vec![]),
575        };
576
577        let meta_infos: Result<Vec<_>> = fields
578            .iter()
579            .map(|f| &f.attrs)
580            .map(|attrs| get_meta_info(&trait_attr, attrs, &allowed_attr_params.field))
581            .collect();
582        let meta_infos = meta_infos?;
583        let full_meta_infos: Vec<_> = meta_infos
584            .into_iter()
585            .map(|info| info.into_full(default_info.clone()))
586            .collect();
587
588        let generics = add_extra_ty_param_bound(&input.generics, &trait_path);
589
590        Ok(State {
591            input,
592            trait_name,
593            trait_module,
594            trait_path,
595            trait_path_params: vec![],
596            trait_attr,
597            method_ident,
598            // input,
599            fields,
600            variants: vec![],
601            variant_states: vec![],
602            variant: Some(variant),
603            derive_type,
604            generics,
605            full_meta_infos,
606            default_info,
607        })
608    }
609    pub fn add_trait_path_type_param(&mut self, param: TokenStream) {
610        self.trait_path_params.push(param);
611    }
612
613    pub fn assert_single_enabled_field<'state>(
614        &'state self,
615    ) -> SingleFieldData<'input, 'state> {
616        if self.derive_type == DeriveType::Enum {
617            panic_one_field(self.trait_name, &self.trait_attr);
618        }
619        let data = self.enabled_fields_data();
620        if data.fields.len() != 1 {
621            panic_one_field(self.trait_name, &self.trait_attr);
622        };
623        SingleFieldData {
624            input_type: data.input_type,
625            field: data.fields[0],
626            field_type: data.field_types[0],
627            member: data.members[0].clone(),
628            info: data.infos[0].clone(),
629            trait_path: data.trait_path,
630            trait_path_with_params: data.trait_path_with_params.clone(),
631            casted_trait: data.casted_traits[0].clone(),
632            impl_generics: data.impl_generics.clone(),
633            ty_generics: data.ty_generics.clone(),
634            where_clause: data.where_clause,
635            multi_field_data: data,
636        }
637    }
638
639    pub fn enabled_fields_data<'state>(&'state self) -> MultiFieldData<'input, 'state> {
640        if self.derive_type == DeriveType::Enum {
641            panic!("cannot derive({}) for enum", self.trait_name)
642        }
643        let fields = self.enabled_fields();
644        let field_idents = self.enabled_fields_idents();
645        let field_indexes = self.enabled_fields_indexes();
646        let field_types: Vec<_> = fields.iter().map(|f| &f.ty).collect();
647        let members: Vec<_> = field_idents
648            .iter()
649            .map(|ident| quote!(self.#ident))
650            .collect();
651        let trait_path = &self.trait_path;
652        let trait_path_with_params = if !self.trait_path_params.is_empty() {
653            let params = self.trait_path_params.iter();
654            quote!(#trait_path<#(#params),*>)
655        } else {
656            self.trait_path.clone()
657        };
658
659        let casted_traits: Vec<_> = field_types
660            .iter()
661            .map(|field_type| quote!(<#field_type as #trait_path_with_params>))
662            .collect();
663        let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
664        let input_type = &self.input.ident;
665        let (variant_name, variant_type) = self.variant.map_or_else(
666            || (None, quote!(#input_type)),
667            |v| {
668                let variant_name = &v.ident;
669                (Some(variant_name), quote!(#input_type::#variant_name))
670            },
671        );
672        MultiFieldData {
673            input_type,
674            variant_type,
675            variant_name,
676            variant_info: self.default_info.clone(),
677            fields,
678            field_types,
679            field_indexes,
680            members,
681            infos: self.enabled_infos(),
682            field_idents,
683            method_ident: &self.method_ident,
684            trait_path,
685            trait_path_with_params,
686            casted_traits,
687            impl_generics,
688            ty_generics,
689            where_clause,
690            state: self,
691        }
692    }
693
694    pub fn enabled_variant_data<'state>(
695        &'state self,
696    ) -> MultiVariantData<'input, 'state> {
697        if self.derive_type != DeriveType::Enum {
698            panic!("can only derive({}) for enum", self.trait_name)
699        }
700        let variants = self.enabled_variants();
701        MultiVariantData {
702            variants,
703            variant_states: self.enabled_variant_states(),
704        }
705    }
706
707    fn enabled_variants(&self) -> Vec<&'input Variant> {
708        self.variants
709            .iter()
710            .zip(self.full_meta_infos.iter().map(|info| info.enabled))
711            .filter(|(_, ig)| *ig)
712            .map(|(v, _)| *v)
713            .collect()
714    }
715
716    fn enabled_variant_states(&self) -> Vec<&State<'input>> {
717        self.variant_states
718            .iter()
719            .zip(self.full_meta_infos.iter().map(|info| info.enabled))
720            .filter(|(_, ig)| *ig)
721            .map(|(v, _)| v)
722            .collect()
723    }
724
725    pub fn enabled_fields(&self) -> Vec<&'input Field> {
726        self.fields
727            .iter()
728            .zip(self.full_meta_infos.iter().map(|info| info.enabled))
729            .filter(|(_, ig)| *ig)
730            .map(|(f, _)| *f)
731            .collect()
732    }
733
734    fn field_idents(&self) -> Vec<TokenStream> {
735        if self.derive_type == DeriveType::Named {
736            self.fields
737                .iter()
738                .map(|f| {
739                    f.ident
740                        .as_ref()
741                        .expect("Tried to get field names of a tuple struct")
742                        .to_token_stream()
743                })
744                .collect()
745        } else {
746            let count = self.fields.len();
747            (0..count)
748                .map(|i| Index::from(i).to_token_stream())
749                .collect()
750        }
751    }
752
753    fn enabled_fields_idents(&self) -> Vec<TokenStream> {
754        self.field_idents()
755            .into_iter()
756            .zip(self.full_meta_infos.iter().map(|info| info.enabled))
757            .filter(|(_, ig)| *ig)
758            .map(|(f, _)| f)
759            .collect()
760    }
761
762    fn enabled_fields_indexes(&self) -> Vec<usize> {
763        self.full_meta_infos
764            .iter()
765            .map(|info| info.enabled)
766            .enumerate()
767            .filter(|(_, ig)| *ig)
768            .map(|(i, _)| i)
769            .collect()
770    }
771    fn enabled_infos(&self) -> Vec<FullMetaInfo> {
772        self.full_meta_infos
773            .iter()
774            .filter(|info| info.enabled)
775            .cloned()
776            .collect()
777    }
778}
779
780#[derive(Clone)]
781pub struct SingleFieldData<'input, 'state> {
782    pub input_type: &'input Ident,
783    pub field: &'input Field,
784    pub field_type: &'input Type,
785    pub member: TokenStream,
786    pub info: FullMetaInfo,
787    pub trait_path: &'state TokenStream,
788    pub trait_path_with_params: TokenStream,
789    pub casted_trait: TokenStream,
790    pub impl_generics: ImplGenerics<'state>,
791    pub ty_generics: TypeGenerics<'state>,
792    pub where_clause: Option<&'state WhereClause>,
793    multi_field_data: MultiFieldData<'input, 'state>,
794}
795
796#[derive(Clone)]
797pub struct MultiFieldData<'input, 'state> {
798    pub input_type: &'input Ident,
799    pub variant_type: TokenStream,
800    pub variant_name: Option<&'input Ident>,
801    pub variant_info: FullMetaInfo,
802    pub fields: Vec<&'input Field>,
803    pub field_types: Vec<&'input Type>,
804    pub field_idents: Vec<TokenStream>,
805    pub field_indexes: Vec<usize>,
806    pub members: Vec<TokenStream>,
807    pub infos: Vec<FullMetaInfo>,
808    pub method_ident: &'state Ident,
809    pub trait_path: &'state TokenStream,
810    pub trait_path_with_params: TokenStream,
811    pub casted_traits: Vec<TokenStream>,
812    pub impl_generics: ImplGenerics<'state>,
813    pub ty_generics: TypeGenerics<'state>,
814    pub where_clause: Option<&'state WhereClause>,
815    pub state: &'state State<'input>,
816}
817
818pub struct MultiVariantData<'input, 'state> {
819    pub variants: Vec<&'input Variant>,
820    pub variant_states: Vec<&'state State<'input>>,
821}
822
823impl<'input, 'state> MultiFieldData<'input, 'state> {
824    pub fn initializer<T: ToTokens>(&self, initializers: &[T]) -> TokenStream {
825        let MultiFieldData {
826            variant_type,
827            field_idents,
828            ..
829        } = self;
830        if self.state.derive_type == DeriveType::Named {
831            quote!(#variant_type{#(#field_idents: #initializers),*})
832        } else {
833            quote!(#variant_type(#(#initializers),*))
834        }
835    }
836    pub fn matcher<T: ToTokens>(
837        &self,
838        indexes: &[usize],
839        bindings: &[T],
840    ) -> TokenStream {
841        let MultiFieldData { variant_type, .. } = self;
842        let full_bindings = (0..self.state.fields.len()).map(|i| {
843            indexes.iter().position(|index| i == *index).map_or_else(
844                || quote!(_),
845                |found_index| bindings[found_index].to_token_stream(),
846            )
847        });
848        if self.state.derive_type == DeriveType::Named {
849            let field_idents = self.state.field_idents();
850            quote!(#variant_type{#(#field_idents: #full_bindings),*})
851        } else {
852            quote!(#variant_type(#(#full_bindings),*))
853        }
854    }
855}
856
857impl<'input, 'state> SingleFieldData<'input, 'state> {
858    pub fn initializer<T: ToTokens>(&self, initializers: &[T]) -> TokenStream {
859        self.multi_field_data.initializer(initializers)
860    }
861}
862
863fn get_meta_info(
864    trait_attr: &str,
865    attrs: &[Attribute],
866    allowed_attr_params: &[&str],
867) -> Result<MetaInfo> {
868    let mut it = attrs
869        .iter()
870        .filter_map(|m| m.parse_meta().ok())
871        .filter(|m| {
872            m.path()
873                .segments
874                .first()
875                .map(|p| p.ident == trait_attr)
876                .unwrap_or_default()
877        });
878
879    let mut info = MetaInfo::default();
880
881    let meta = if let Some(meta) = it.next() {
882        meta
883    } else {
884        return Ok(info);
885    };
886
887    if allowed_attr_params.is_empty() {
888        return Err(Error::new(meta.span(), "Attribute is not allowed here"));
889    }
890
891    info.enabled = Some(true);
892
893    if let Some(another_meta) = it.next() {
894        return Err(Error::new(
895            another_meta.span(),
896            "Only a single attribute is allowed",
897        ));
898    }
899
900    let list = match meta.clone() {
901        ParsedMeta::Path(_) => {
902            if allowed_attr_params.contains(&"ignore") {
903                return Ok(info);
904            } else {
905                return Err(Error::new(
906                    meta.span(),
907                    format!(
908                        "Empty attribute is not allowed, add one of the following parameters: {}",
909                        allowed_attr_params.join(", "),
910                    ),
911                ));
912            }
913        }
914        ParsedMeta::List(list) => list,
915        ParsedMeta::NameValue(val) => {
916            return Err(Error::new(
917                val.span(),
918                "Attribute doesn't support name-value format here",
919            ));
920        }
921    };
922
923    parse_punctuated_nested_meta(&mut info, &list.nested, allowed_attr_params, None)?;
924
925    Ok(info)
926}
927
928fn parse_punctuated_nested_meta(
929    info: &mut MetaInfo,
930    meta: &Punctuated<NestedMeta, Token![,]>,
931    allowed_attr_params: &[&str],
932    wrapper_name: Option<&str>,
933) -> Result<()> {
934    for meta in meta.iter() {
935        let meta = match meta {
936            NestedMeta::Meta(meta) => meta,
937            NestedMeta::Lit(lit) => {
938                return Err(Error::new(
939                    lit.span(),
940                    "Attribute doesn't support literals here",
941                ))
942            }
943        };
944
945        match meta {
946            ParsedMeta::List(list) if list.path.is_ident("not") => {
947                if wrapper_name.is_some() {
948                    // Only single top-level `not` attribute is allowed.
949                    return Err(Error::new(
950                        list.span(),
951                        "Attribute doesn't support multiple multiple or nested `not` parameters",
952                    ));
953                }
954                parse_punctuated_nested_meta(
955                    info,
956                    &list.nested,
957                    allowed_attr_params,
958                    Some("not"),
959                )?;
960            }
961
962            ParsedMeta::List(list) => {
963                let path = &list.path;
964                if !allowed_attr_params.iter().any(|param| path.is_ident(param)) {
965                    return Err(Error::new(
966                        meta.span(),
967                        format!(
968                            "Attribute nested parameter not supported. \
969                             Supported attribute parameters are: {}",
970                            allowed_attr_params.join(", "),
971                        ),
972                    ));
973                }
974
975                let mut parse_nested = true;
976
977                let attr_name = path.get_ident().unwrap().to_string();
978                match (wrapper_name, attr_name.as_str()) {
979                    (None, "owned") => info.owned = Some(true),
980                    (None, "ref") => info.ref_ = Some(true),
981                    (None, "ref_mut") => info.ref_mut = Some(true),
982
983                    #[cfg(any(feature = "from", feature = "into"))]
984                    (None, "types")
985                    | (Some("owned"), "types")
986                    | (Some("ref"), "types")
987                    | (Some("ref_mut"), "types") => {
988                        parse_nested = false;
989                        for meta in &list.nested {
990                            let typ: syn::Type = match meta {
991                                NestedMeta::Meta(meta) => {
992                                    let path = if let ParsedMeta::Path(p) = meta {
993                                        p
994                                    } else {
995                                        return Err(Error::new(
996                                            meta.span(),
997                                            format!(
998                                                "Attribute doesn't support type {}",
999                                                quote! { #meta },
1000                                            ),
1001                                        ));
1002                                    };
1003                                    syn::TypePath {
1004                                        qself: None,
1005                                        path: path.clone(),
1006                                    }
1007                                    .into()
1008                                }
1009                                NestedMeta::Lit(syn::Lit::Str(s)) => s.parse()?,
1010                                NestedMeta::Lit(lit) => return Err(Error::new(
1011                                    lit.span(),
1012                                    "Attribute doesn't support nested literals here",
1013                                )),
1014                            };
1015
1016                            for ref_type in wrapper_name
1017                                .map(|n| vec![RefType::from_attr_name(n)])
1018                                .unwrap_or_else(|| {
1019                                    vec![RefType::No, RefType::Ref, RefType::Mut]
1020                                })
1021                            {
1022                                if info
1023                                    .types
1024                                    .entry(ref_type)
1025                                    .or_default()
1026                                    .replace(typ.clone())
1027                                    .is_some()
1028                                {
1029                                    return Err(Error::new(
1030                                        typ.span(),
1031                                        format!(
1032                                            "Duplicate type `{}` specified",
1033                                            quote! { #path },
1034                                        ),
1035                                    ));
1036                                }
1037                            }
1038                        }
1039                    }
1040
1041                    _ => {
1042                        return Err(Error::new(
1043                            list.span(),
1044                            format!(
1045                                "Attribute doesn't support nested parameter `{}` here",
1046                                quote! { #path },
1047                            ),
1048                        ))
1049                    }
1050                };
1051
1052                if parse_nested {
1053                    parse_punctuated_nested_meta(
1054                        info,
1055                        &list.nested,
1056                        allowed_attr_params,
1057                        Some(&attr_name),
1058                    )?;
1059                }
1060            }
1061
1062            ParsedMeta::Path(path) => {
1063                if !allowed_attr_params.iter().any(|param| path.is_ident(param)) {
1064                    return Err(Error::new(
1065                        meta.span(),
1066                        format!(
1067                            "Attribute parameter not supported. \
1068                             Supported attribute parameters are: {}",
1069                            allowed_attr_params.join(", "),
1070                        ),
1071                    ));
1072                }
1073
1074                let attr_name = path.get_ident().unwrap().to_string();
1075                match (wrapper_name, attr_name.as_str()) {
1076                    (None, "ignore") => info.enabled = Some(false),
1077                    (None, "forward") => info.forward = Some(true),
1078                    (Some("not"), "forward") => info.forward = Some(false),
1079                    (None, "owned") => info.owned = Some(true),
1080                    (None, "ref") => info.ref_ = Some(true),
1081                    (None, "ref_mut") => info.ref_mut = Some(true),
1082                    (None, "source") => info.source = Some(true),
1083                    (Some("not"), "source") => info.source = Some(false),
1084                    (None, "backtrace") => info.backtrace = Some(true),
1085                    (Some("not"), "backtrace") => info.backtrace = Some(false),
1086                    _ => {
1087                        return Err(Error::new(
1088                            path.span(),
1089                            format!(
1090                                "Attribute doesn't support parameter `{}` here",
1091                                quote! { #path }
1092                            ),
1093                        ))
1094                    }
1095                }
1096            }
1097
1098            ParsedMeta::NameValue(val) => {
1099                return Err(Error::new(
1100                    val.span(),
1101                    "Attribute doesn't support name-value parameters here",
1102                ))
1103            }
1104        }
1105    }
1106
1107    Ok(())
1108}
1109
1110#[derive(Clone, Debug, Default)]
1111pub struct FullMetaInfo {
1112    pub enabled: bool,
1113    pub forward: bool,
1114    pub owned: bool,
1115    pub ref_: bool,
1116    pub ref_mut: bool,
1117    pub info: MetaInfo,
1118}
1119
1120#[derive(Clone, Debug, Default)]
1121pub struct MetaInfo {
1122    pub enabled: Option<bool>,
1123    pub forward: Option<bool>,
1124    pub owned: Option<bool>,
1125    pub ref_: Option<bool>,
1126    pub ref_mut: Option<bool>,
1127    pub source: Option<bool>,
1128    pub backtrace: Option<bool>,
1129    #[cfg(any(feature = "from", feature = "into"))]
1130    pub types: HashMap<RefType, HashSet<syn::Type>>,
1131}
1132
1133impl MetaInfo {
1134    fn into_full(self, defaults: FullMetaInfo) -> FullMetaInfo {
1135        FullMetaInfo {
1136            enabled: self.enabled.unwrap_or(defaults.enabled),
1137            forward: self.forward.unwrap_or(defaults.forward),
1138            owned: self.owned.unwrap_or(defaults.owned),
1139            ref_: self.ref_.unwrap_or(defaults.ref_),
1140            ref_mut: self.ref_mut.unwrap_or(defaults.ref_mut),
1141            info: self,
1142        }
1143    }
1144}
1145
1146impl FullMetaInfo {
1147    pub fn ref_types(&self) -> Vec<RefType> {
1148        let mut ref_types = vec![];
1149        if self.owned {
1150            ref_types.push(RefType::No);
1151        }
1152        if self.ref_ {
1153            ref_types.push(RefType::Ref);
1154        }
1155        if self.ref_mut {
1156            ref_types.push(RefType::Mut);
1157        }
1158        ref_types
1159    }
1160
1161    #[cfg(any(feature = "from", feature = "into"))]
1162    pub fn additional_types(&self, ref_type: RefType) -> HashSet<syn::Type> {
1163        self.info.types.get(&ref_type).cloned().unwrap_or_default()
1164    }
1165}
1166
1167pub fn get_if_type_parameter_used_in_type(
1168    type_parameters: &HashSet<syn::Ident>,
1169    ty: &syn::Type,
1170) -> Option<syn::Type> {
1171    if is_type_parameter_used_in_type(type_parameters, ty) {
1172        match ty {
1173            syn::Type::Reference(syn::TypeReference { elem: ty, .. }) => {
1174                Some((**ty).clone())
1175            }
1176            ty => Some(ty.clone()),
1177        }
1178    } else {
1179        None
1180    }
1181}
1182
1183pub fn is_type_parameter_used_in_type(
1184    type_parameters: &HashSet<syn::Ident>,
1185    ty: &syn::Type,
1186) -> bool {
1187    match ty {
1188        syn::Type::Path(ty) => {
1189            if let Some(qself) = &ty.qself {
1190                if is_type_parameter_used_in_type(type_parameters, &qself.ty) {
1191                    return true;
1192                }
1193            }
1194
1195            if let Some(segment) = ty.path.segments.first() {
1196                if type_parameters.contains(&segment.ident) {
1197                    return true;
1198                }
1199            }
1200
1201            ty.path.segments.iter().any(|segment| {
1202                if let syn::PathArguments::AngleBracketed(arguments) =
1203                    &segment.arguments
1204                {
1205                    arguments.args.iter().any(|argument| match argument {
1206                        syn::GenericArgument::Type(ty) => {
1207                            is_type_parameter_used_in_type(type_parameters, ty)
1208                        }
1209                        syn::GenericArgument::Constraint(constraint) => {
1210                            type_parameters.contains(&constraint.ident)
1211                        }
1212                        _ => false,
1213                    })
1214                } else {
1215                    false
1216                }
1217            })
1218        }
1219
1220        syn::Type::Reference(ty) => {
1221            is_type_parameter_used_in_type(type_parameters, &ty.elem)
1222        }
1223
1224        _ => false,
1225    }
1226}