structmeta_derive/
struct_meta.rs

1use crate::syn_utils::*;
2use proc_macro2::{Span, TokenStream};
3use quote::{format_ident, quote, quote_spanned};
4use std::collections::BTreeMap;
5use syn::{
6    ext::IdentExt,
7    parse::{Parse, ParseStream},
8    parse_quote,
9    punctuated::Punctuated,
10    spanned::Spanned,
11    Attribute, Data, DeriveInput, Field, Fields, GenericArgument, Ident, LitStr, PathArguments,
12    Result, Token, Type,
13};
14
15pub fn derive_struct_meta(input: DeriveInput) -> Result<TokenStream> {
16    if let Data::Struct(data) = &input.data {
17        let mut args = ArgsForStruct::default();
18        for attr in &input.attrs {
19            if attr.path().is_ident("struct_meta") {
20                args.parse_from_attr(attr)?;
21            }
22        }
23        let ps = Params::from_fields(&data.fields, &args)?;
24        let body = ps.build();
25        impl_trait_result(
26            &input,
27            &parse_quote!(::structmeta::helpers::exports::syn::parse::Parse),
28            &[],
29            quote! {
30                fn parse(input: ::structmeta::helpers::exports::syn::parse::ParseStream<'_>) -> ::structmeta::helpers::exports::syn::Result<Self> {
31                    #body
32                }
33            },
34            args.dump,
35        )
36    } else {
37        let span = input.span();
38        bail!(span, "`#[derive(StructMeta)]` supports only struct.")
39    }
40}
41struct Params<'a> {
42    fields: &'a Fields,
43    unnamed_required: Vec<UnnamedParam<'a>>,
44    unnamed_optional: Vec<UnnamedParam<'a>>,
45    unnamed_variadic: Option<UnnamedParam<'a>>,
46    named: BTreeMap<String, NamedParam<'a>>,
47    rest: Option<RestParam<'a>>,
48    name_filter: NameFilter,
49}
50impl<'a> Params<'a> {
51    fn from_fields(fields: &'a Fields, args: &ArgsForStruct) -> Result<Self> {
52        let mut unnamed_required = Vec::new();
53        let mut unnamed_optional = Vec::new();
54        let mut unnamed_variadic = None;
55        let mut named = BTreeMap::new();
56        let mut rest = None;
57        for (index, field) in fields.iter().enumerate() {
58            let span = field.span();
59            match Param::from_field(index, field)? {
60                Param::Unnamed(p) => {
61                    if unnamed_variadic.is_some() {
62                        bail!(
63                            span,
64                            "cannot use unnamed parameter after variadic parameter."
65                        )
66                    }
67                    if p.is_vec {
68                        unnamed_variadic = Some(p);
69                    } else if p.is_option {
70                        unnamed_optional.push(p);
71                    } else {
72                        if !unnamed_optional.is_empty() {
73                            bail!(
74                                span,
75                                "cannot use non optional parameter after variadic parameter."
76                            )
77                        }
78                        unnamed_required.push(p);
79                    }
80                }
81                Param::Named(p) => {
82                    if named.contains_key(&p.name) {
83                        bail!(p.name_span, "`{}` is already exists.", p.name);
84                    }
85                    named.insert(p.name.clone(), p);
86                }
87                Param::Rest(p) => {
88                    if rest.is_some() {
89                        bail!(span, "cannot use rest parameter twice.")
90                    }
91                    rest = Some(p);
92                }
93            }
94        }
95        Ok(Self {
96            fields,
97            unnamed_required,
98            unnamed_optional,
99            unnamed_variadic,
100            named,
101            rest,
102            name_filter: args.name_filter(),
103        })
104    }
105    fn build(&self) -> TokenStream {
106        let mut is_next = false;
107        let mut ts = TokenStream::new();
108        let mut ctor_args = vec![TokenStream::new(); self.fields.len()];
109        for (index, p) in self.unnamed_required.iter().enumerate() {
110            if is_next {
111                let msg = format!(
112                    "expected least {} arguments but {} argument was supplied",
113                    self.unnamed_required.len(),
114                    index,
115                );
116                ts.extend(quote! {
117                    if input.is_empty () {
118                        return Err(::structmeta::helpers::exports::syn::Error::new(input.span(), #msg));
119                    }
120                    input.parse::<::structmeta::helpers::exports::syn::Token![,]>()?;
121                });
122            }
123            is_next = true;
124            ts.extend(p.info.build_let_parse());
125            p.build_ctor_arg(false, &mut ctor_args);
126        }
127
128        let mut arms_unnamed = Vec::new();
129        for (index, p) in self.unnamed_optional.iter().enumerate() {
130            ts.extend(p.info.build_let_none());
131            arms_unnamed.push(p.build_arm_parse_value(index));
132            p.build_ctor_arg(true, &mut ctor_args);
133        }
134        if let Some(p) = &self.unnamed_variadic {
135            ts.extend(p.info.build_let_vec_new());
136            arms_unnamed.push(p.build_arm_parse_vec_item());
137            p.build_ctor_arg(false, &mut ctor_args);
138        } else {
139            arms_unnamed.push(quote! {
140                _ => { return Err(input.error("too many unnamed parameter")); }
141            });
142        }
143        for p in self.named.values() {
144            ts.extend(p.build_let());
145            p.build_ctor_arg(&mut ctor_args);
146        }
147        let (flag_ps, flag_rest) = self.named_ps(|p| p.is_flag());
148        let (name_value_ps, name_value_rest) = self.named_ps(|p| p.is_name_value());
149        let (name_args_ps, name_args_rest) = self.named_ps(|p| p.is_name_args());
150
151        let mut arms_named = Vec::new();
152        for (index, p) in flag_ps.iter().enumerate() {
153            arms_named.push(p.build_arm_parse(index, ArgKind::Flag));
154        }
155        for (index, p) in name_value_ps.iter().enumerate() {
156            arms_named.push(p.build_arm_parse(index, ArgKind::NameValue));
157        }
158        for (index, p) in name_args_ps.iter().enumerate() {
159            arms_named.push(p.build_arm_parse(index, ArgKind::NameArgs));
160        }
161        if let Some(p) = &self.rest {
162            ts.extend(p.build_let());
163            p.build_ctor_arg(&mut ctor_args);
164            if flag_rest {
165                arms_named.push(p.build_arm_parse(ArgKind::Flag));
166            }
167            if name_value_rest {
168                arms_named.push(p.build_arm_parse(ArgKind::NameValue));
169            }
170            if name_args_rest {
171                arms_named.push(p.build_arm_parse(ArgKind::NameArgs));
172            }
173        }
174
175        let flag_names = NamedParam::names(&flag_ps);
176        let name_value_names = NamedParam::names(&name_value_ps);
177        let name_args_names = NamedParam::names(&name_args_ps);
178        let no_unnamed = self.unnamed_optional.is_empty() && self.unnamed_variadic.is_none();
179        let ctor_args = match &self.fields {
180            Fields::Named(_) => {
181                quote!({ #(#ctor_args,)*})
182            }
183            Fields::Unnamed(_) => {
184                quote!(( #(#ctor_args,)*))
185            }
186            Fields::Unit => {
187                quote!()
188            }
189        };
190
191        let ts_parse_unnamed = if !self.unnamed_optional.is_empty()
192            || self.unnamed_variadic.is_some()
193        {
194            quote! {
195                if named_used {
196                    return Err(input.error("cannot use unnamed parameter after named parameter"));
197                }
198                match unnamed_index {
199                    #(#arms_unnamed)*
200                }
201                unnamed_index += 1;
202            }
203        } else {
204            quote! {
205                return Err(input.error("cannot use unnamed parameter"));
206            }
207        };
208        let name_filter = self.name_filter.to_code();
209
210        ts.extend(quote! {
211            let mut is_next = #is_next;
212            let mut unnamed_index = 0;
213            let mut named_used = false;
214            while !input.is_empty() {
215                if is_next {
216                    input.parse::<::structmeta::helpers::exports::syn::Token![,]>()?;
217                    if input.is_empty() {
218                        break;
219                    }
220                }
221                is_next = true;
222                if let Some((index, span)) = ::structmeta::helpers::try_parse_name(input,
223                    &[#(#flag_names,)*],
224                    #flag_rest,
225                    &[#(#name_value_names,)*],
226                    #name_value_rest,
227                    &[#(#name_args_names,)*],
228                    #name_args_rest,
229                    #no_unnamed,
230                    #name_filter)?
231                {
232                    named_used = true;
233                    match index {
234                        #(#arms_named)*
235                        _ => unreachable!()
236                    }
237
238                } else {
239                    #ts_parse_unnamed
240                }
241            }
242            Ok(Self #ctor_args)
243        });
244
245        ts
246    }
247    fn named_ps(&self, f: impl Fn(&NamedParamType<'a>) -> bool) -> (Vec<&NamedParam<'a>>, bool) {
248        (
249            self.named.values().filter(|p| f(&p.ty)).collect(),
250            if let Some(p) = &self.rest {
251                f(&p.ty)
252            } else {
253                false
254            },
255        )
256    }
257}
258
259enum Param<'a> {
260    Unnamed(UnnamedParam<'a>),
261    Named(NamedParam<'a>),
262    Rest(RestParam<'a>),
263}
264
265impl<'a> Param<'a> {
266    fn from_field(index: usize, field: &'a Field) -> Result<Self> {
267        let mut name = None;
268        let mut name_specified = false;
269        let mut unnamed = false;
270        for attr in &field.attrs {
271            if attr.path().is_ident("struct_meta") {
272                let a = attr.parse_args::<ArgsForField>()?;
273                if let Some(a_name) = a.name {
274                    name = Some((a_name.value(), a_name.span()));
275                    name_specified = true;
276                }
277                if a.unnamed {
278                    unnamed = true;
279                }
280            }
281        }
282        if name.is_none() {
283            if let Some(ident) = &field.ident {
284                name = Some((ident.unraw().to_string(), ident.span()));
285            }
286        }
287        if unnamed {
288            name = None;
289        }
290
291        let mut is_map = false;
292        let mut is_option = false;
293
294        let ty = if let (false, Some(ty)) = (name_specified, get_hash_map_string_element(&field.ty))
295        {
296            is_map = true;
297            ty
298        } else if let Some(ty) = get_option_element(&field.ty) {
299            is_option = true;
300            ty
301        } else {
302            &field.ty
303        };
304
305        let info = ParamInfo::new(index, field, ty);
306        let ty = NamedParamType::from_type(ty, !is_map && !is_option);
307        let this = if is_map {
308            Param::Rest(RestParam { info, ty })
309        } else if let Some((name, name_span)) = name {
310            Param::Named(NamedParam {
311                info,
312                name,
313                name_span,
314                ty,
315                is_option,
316            })
317        } else if let NamedParamType::Value { ty, is_vec } = ty {
318            Param::Unnamed(UnnamedParam {
319                info,
320                ty,
321                is_option,
322                is_vec,
323            })
324        } else {
325            bail!(
326                info.span(),
327                "this field type cannot be used as unnamed parameter."
328            )
329        };
330        Ok(this)
331    }
332}
333
334struct ParamInfo<'a> {
335    index: usize,
336    field: &'a Field,
337    ty: &'a Type,
338    temp_ident: Ident,
339}
340impl<'a> ParamInfo<'a> {
341    fn new(index: usize, field: &'a Field, ty: &'a Type) -> Self {
342        let temp_ident = format_ident!("_value_{}", index);
343        Self {
344            index,
345            field,
346            ty,
347            temp_ident,
348        }
349    }
350    fn span(&self) -> Span {
351        self.field.span()
352    }
353    fn build_let_none(&self) -> TokenStream {
354        let temp_ident = &self.temp_ident;
355        let ty = &self.ty;
356        quote!(let mut #temp_ident : Option<#ty> = None;)
357    }
358    fn build_let_vec_new(&self) -> TokenStream {
359        let temp_ident = &self.temp_ident;
360        let ty = &self.ty;
361        quote!(let mut #temp_ident = <#ty>::new();)
362    }
363    fn build_let_parse(&self) -> TokenStream {
364        let temp_ident = &self.temp_ident;
365        let ty = &self.field.ty;
366        quote_spanned!(self.span()=> let #temp_ident = input.parse::<#ty>()?;)
367    }
368}
369
370struct RestParam<'a> {
371    info: ParamInfo<'a>,
372    ty: NamedParamType<'a>,
373}
374
375struct NamedParam<'a> {
376    info: ParamInfo<'a>,
377    name: String,
378    name_span: Span,
379    ty: NamedParamType<'a>,
380    is_option: bool,
381}
382
383struct UnnamedParam<'a> {
384    info: ParamInfo<'a>,
385    ty: &'a Type,
386    is_option: bool,
387    is_vec: bool,
388}
389impl<'a> NamedParam<'a> {
390    fn build_let(&self) -> TokenStream {
391        let temp_ident = &self.info.temp_ident;
392        quote!(let mut #temp_ident = None;)
393    }
394    fn build_arm_parse(&self, index: usize, kind: ArgKind) -> TokenStream {
395        let temp_ident = &self.info.temp_ident;
396        let msg = format!("parameter `{}` specified more than once", self.name);
397        let span = self.info.field.span();
398        let expr = self.ty.build_parse_expr(kind, span);
399        let var = kind.to_helper_name_index_variant();
400        quote_spanned! { span=>
401            ::structmeta::helpers::NameIndex::#var(Ok(#index)) => {
402                if #temp_ident.is_some() {
403                    return Err(::structmeta::helpers::exports::syn::Error::new(span, #msg));
404                }
405                #temp_ident = Some(#expr);
406            }
407        }
408    }
409    fn names<'b>(ps: &[&'b Self]) -> Vec<&'b str> {
410        ps.iter().map(|x| x.name.as_str()).collect()
411    }
412    fn build_ctor_arg(&self, ctor_args: &mut [TokenStream]) {
413        let temp_ident = &self.info.temp_ident;
414        let value = if self.is_option {
415            quote!(#temp_ident)
416        } else {
417            match self.ty {
418                NamedParamType::Flag => quote!(::structmeta::Flag { span: #temp_ident }),
419                NamedParamType::Bool => quote!(#temp_ident.is_some()),
420                NamedParamType::Value { .. } | NamedParamType::NameValue { .. } => {
421                    let msg = format!("missing argument `{} = ...`", self.name);
422                    quote!(#temp_ident.ok_or_else(|| ::structmeta::helpers::exports::syn::Error::new(::structmeta::helpers::exports::proc_macro2::Span::call_site(), #msg))?)
423                }
424                NamedParamType::NameArgs { .. } => {
425                    let msg = format!("missing argument `{}(...)`", self.name);
426                    quote!(#temp_ident.ok_or_else(|| ::structmeta::helpers::exports::syn::Error::new(::structmeta::helpers::exports::proc_macro2::Span::call_site(), #msg))?)
427                }
428            }
429        };
430        build_ctor_arg(&self.info, value, ctor_args)
431    }
432}
433impl<'a> RestParam<'a> {
434    fn build_let(&self) -> TokenStream {
435        let temp_ident = &self.info.temp_ident;
436        quote!(let mut #temp_ident = ::std::collections::HashMap::new();)
437    }
438    fn build_arm_parse(&self, kind: ArgKind) -> TokenStream {
439        let temp_ident = &self.info.temp_ident;
440        let span = self.info.field.span();
441        let expr = self.ty.build_parse_expr(kind, span);
442        let var = kind.to_helper_name_index_variant();
443        quote_spanned! { span=>
444            ::structmeta::helpers::NameIndex::#var(Err(name)) => {
445                if #temp_ident.insert(name.to_string(), #expr).is_some() {
446                    return Err(::structmeta::helpers::exports::syn::Error::new(span, format!("parameter `{}` specified more than once", name)));
447                }
448            }
449        }
450    }
451    fn build_ctor_arg(&self, ctor_args: &mut [TokenStream]) {
452        let temp_ident = &self.info.temp_ident;
453        build_ctor_arg(&self.info, quote!(#temp_ident), ctor_args)
454    }
455}
456impl<'a> UnnamedParam<'a> {
457    fn build_arm_parse_value(&self, index: usize) -> TokenStream {
458        let temp_ident = &self.info.temp_ident;
459        let span = self.info.field.span();
460        let expr = build_parse_expr(self.ty, span);
461        quote_spanned! { span=>
462            #index => {
463                #temp_ident = Some(#expr);
464            }
465        }
466    }
467    fn build_arm_parse_vec_item(&self) -> TokenStream {
468        let temp_ident = &self.info.temp_ident;
469        let span = self.info.field.span();
470        let expr = build_parse_expr(self.ty, span);
471        quote_spanned! { self.info.field.span()=>
472            _ => {
473                #temp_ident.push(#expr);
474            }
475        }
476    }
477    fn build_ctor_arg(&self, var_is_option: bool, ctor_args: &mut [TokenStream]) {
478        let temp_ident = &self.info.temp_ident;
479        let value = match (var_is_option, self.is_option) {
480            (false, false) | (true, true) => {
481                quote!(#temp_ident)
482            }
483            (true, false) => {
484                quote!(#temp_ident.unwrap())
485            }
486            _ => {
487                unreachable!()
488            }
489        };
490        build_ctor_arg(&self.info, value, ctor_args)
491    }
492}
493fn build_ctor_arg(info: &ParamInfo, value: TokenStream, ctor_args: &mut [TokenStream]) {
494    let value = if let Some(ident) = &info.field.ident {
495        quote!(#ident : #value)
496    } else {
497        value
498    };
499    ctor_args[info.index] = value;
500}
501
502mod kw {
503    use syn::custom_keyword;
504
505    custom_keyword!(dump);
506    custom_keyword!(name_filter);
507    custom_keyword!(name);
508    custom_keyword!(unnamed);
509}
510
511#[derive(Debug, Clone, Copy)]
512enum NameFilter {
513    None,
514    SnakeCase,
515}
516impl NameFilter {
517    fn to_code(self) -> TokenStream {
518        match self {
519            NameFilter::None => quote!(&|_| true),
520            NameFilter::SnakeCase => quote!(&::structmeta::helpers::is_snake_case),
521        }
522    }
523}
524
525#[derive(Debug, Default, Clone, Copy)]
526struct ArgsForStruct {
527    dump: bool,
528    name_filter: Option<NameFilter>,
529}
530impl ArgsForStruct {
531    fn parse_from_attr(&mut self, attr: &Attribute) -> Result<()> {
532        let args = attr.parse_args_with(Punctuated::<ArgForStruct, Token![,]>::parse_terminated)?;
533        for arg in args.into_iter() {
534            match arg {
535                ArgForStruct::Dump(_) => self.dump = true,
536                ArgForStruct::NameFilter { span, value } => {
537                    if self.name_filter.is_some() {
538                        bail!(span, "`name_filter` cannot be specified twice");
539                    }
540                    self.name_filter = Some(value);
541                }
542            }
543        }
544        Ok(())
545    }
546    fn name_filter(&self) -> NameFilter {
547        self.name_filter.unwrap_or(NameFilter::None)
548    }
549}
550
551enum ArgForStruct {
552    Dump(kw::dump),
553    NameFilter { span: Span, value: NameFilter },
554}
555impl Parse for ArgForStruct {
556    fn parse(input: ParseStream) -> Result<Self> {
557        if input.peek(kw::dump) {
558            return Ok(Self::Dump(input.parse()?));
559        }
560        if input.peek(kw::name_filter) {
561            let kw_name_filter: kw::name_filter = input.parse()?;
562            let _eq: Token![=] = input.parse()?;
563            let s: LitStr = input.parse()?;
564            let value = match s.value().as_str() {
565                "snake_case" => NameFilter::SnakeCase,
566                _ => {
567                    bail!(s.span(), "expected \"snake_case\"")
568                }
569            };
570            return Ok(Self::NameFilter {
571                span: kw_name_filter.span,
572                value,
573            });
574        }
575        Err(input.error("usage : #[struct_meta(dump)]"))
576    }
577}
578
579struct ArgsForField {
580    name: Option<LitStr>,
581    unnamed: bool,
582}
583impl Parse for ArgsForField {
584    fn parse(input: ParseStream) -> Result<Self> {
585        let mut name = None;
586        let mut unnamed = false;
587        for p in Punctuated::<_, Token![,]>::parse_terminated(input)?.into_iter() {
588            match p {
589                ArgForField::Name { value, .. } => name = Some(value),
590                ArgForField::Unnamed { .. } => unnamed = true,
591            }
592        }
593        Ok(Self { name, unnamed })
594    }
595}
596
597enum ArgForField {
598    Name {
599        _name_token: kw::name,
600        _eq_token: Token![=],
601        value: LitStr,
602    },
603    Unnamed {
604        _unnamed_token: kw::unnamed,
605    },
606}
607impl Parse for ArgForField {
608    fn parse(input: ParseStream) -> Result<Self> {
609        if input.peek(kw::name) && input.peek2(Token![=]) {
610            let name_token = input.parse()?;
611            let eq_token = input.parse()?;
612            let value = input.parse()?;
613            Ok(Self::Name {
614                _name_token: name_token,
615                _eq_token: eq_token,
616                value,
617            })
618        } else if input.peek(kw::unnamed) {
619            Ok(Self::Unnamed {
620                _unnamed_token: input.parse()?,
621            })
622        } else {
623            Err(input.error("expected `name = \"...\"` or `unnamed`."))
624        }
625    }
626}
627
628enum NamedParamType<'a> {
629    Bool,
630    Flag,
631    Value {
632        ty: &'a Type,
633        is_vec: bool,
634    },
635    NameValue {
636        ty: &'a Type,
637        is_option: bool,
638    },
639    NameArgs {
640        ty: &'a Type,
641        is_option: bool,
642        is_vec: bool,
643    },
644}
645
646impl<'a> NamedParamType<'a> {
647    fn from_type(ty: &'a Type, may_flag: bool) -> Self {
648        if may_flag && is_bool(ty) {
649            Self::Bool
650        } else if may_flag && is_flag(ty) {
651            Self::Flag
652        } else if let Some(mut ty) = get_name_value_element(ty) {
653            let mut is_option = false;
654            if let Some(e) = get_option_element(ty) {
655                is_option = true;
656                ty = e;
657            }
658            Self::NameValue { ty, is_option }
659        } else if let Some(mut ty) = get_name_args_element(ty) {
660            let mut is_option = false;
661            if let Some(e) = get_option_element(ty) {
662                is_option = true;
663                ty = e;
664            }
665            let mut is_vec = false;
666            if let Some(e) = get_vec_element(ty) {
667                is_vec = true;
668                ty = e;
669            }
670            Self::NameArgs {
671                ty,
672                is_option,
673                is_vec,
674            }
675        } else {
676            let mut ty = ty;
677            let mut is_vec = false;
678            if let Some(e) = get_vec_element(ty) {
679                is_vec = true;
680                ty = e;
681            }
682            Self::Value { ty, is_vec }
683        }
684    }
685    fn is_flag(&self) -> bool {
686        match self {
687            NamedParamType::Bool | NamedParamType::Flag => true,
688            NamedParamType::Value { .. } => false,
689            NamedParamType::NameValue { is_option, .. }
690            | NamedParamType::NameArgs { is_option, .. } => *is_option,
691        }
692    }
693    fn is_name_value(&self) -> bool {
694        match self {
695            NamedParamType::Bool | NamedParamType::Flag => false,
696            NamedParamType::Value { is_vec, .. } => !is_vec,
697            NamedParamType::NameValue { .. } => true,
698            NamedParamType::NameArgs { .. } => false,
699        }
700    }
701    fn is_name_args(&self) -> bool {
702        match self {
703            NamedParamType::Bool | NamedParamType::Flag => false,
704            NamedParamType::Value { is_vec, .. } => *is_vec,
705            NamedParamType::NameValue { .. } => false,
706            NamedParamType::NameArgs { .. } => true,
707        }
708    }
709    fn build_parse_expr(&self, kind: ArgKind, span: Span) -> TokenStream {
710        match self {
711            NamedParamType::Bool | NamedParamType::Flag => quote!(span),
712            NamedParamType::Value { ty, is_vec } => {
713                if *is_vec {
714                    build_parse_expr_name_args(ty, *is_vec, span)
715                } else {
716                    build_parse_expr(ty, span)
717                }
718            }
719            NamedParamType::NameValue { ty, is_option } => {
720                let value = if kind == ArgKind::Flag && *is_option {
721                    quote!(None)
722                } else {
723                    let value = build_parse_expr(ty, span);
724                    if *is_option {
725                        quote!(Some(#value))
726                    } else {
727                        value
728                    }
729                };
730                quote!(::structmeta::NameValue { name_span : span, value: #value })
731            }
732            NamedParamType::NameArgs {
733                ty,
734                is_option,
735                is_vec,
736            } => {
737                let args = if kind == ArgKind::Flag && *is_option {
738                    quote!(None)
739                } else {
740                    let args = build_parse_expr_name_args(ty, *is_vec, span);
741                    if *is_option {
742                        quote!(Some(#args))
743                    } else {
744                        args
745                    }
746                };
747                quote!(structmeta::NameArgs { name_span : span, args: #args })
748            }
749        }
750    }
751}
752
753fn build_parse_expr(ty: &Type, span: Span) -> TokenStream {
754    quote_spanned!(span=> input.parse::<#ty>()?)
755}
756fn build_parse_expr_name_args(ty: &Type, is_vec: bool, span: Span) -> TokenStream {
757    let value = if is_vec {
758        quote_spanned!(span=> ::structmeta::helpers::exports::syn::punctuated::Punctuated::<#ty, ::structmeta::helpers::exports::syn::Token![,]>::parse_terminated(&content)?.into_iter().collect())
759    } else {
760        quote_spanned!(span=> content.parse::<#ty>()?)
761    };
762    quote! {
763        {
764            let content;
765            ::structmeta::helpers::exports::syn::parenthesized!(content in input);
766            #value
767        }
768    }
769}
770
771#[derive(Eq, PartialEq, Debug, Copy, Clone)]
772enum ArgKind {
773    Flag,
774    NameValue,
775    NameArgs,
776}
777impl ArgKind {
778    fn to_helper_name_index_variant(self) -> TokenStream {
779        match self {
780            Self::Flag => quote!(Flag),
781            Self::NameValue => quote!(NameValue),
782            Self::NameArgs => quote!(NameArgs),
783        }
784    }
785}
786
787fn get_option_element(ty: &Type) -> Option<&Type> {
788    get_element(ty, &[&["std", "option"], &["core", "option"]], "Option")
789}
790fn get_vec_element(ty: &Type) -> Option<&Type> {
791    get_element(ty, &[&["std", "vec"], &["alloc", "vec"]], "Vec")
792}
793fn get_name_value_element(ty: &Type) -> Option<&Type> {
794    get_element(ty, NS_STRUCTMETA, "NameValue")
795}
796fn get_name_args_element(ty: &Type) -> Option<&Type> {
797    get_element(ty, NS_STRUCTMETA, "NameArgs")
798}
799fn get_hash_map_element(ty: &Type) -> Option<(&Type, &Type)> {
800    get_element2(
801        ty,
802        &[&["std", "collections"], &["std", "collections", "hash_map"]],
803        "HashMap",
804    )
805}
806fn get_hash_map_string_element(ty: &Type) -> Option<&Type> {
807    let (ty_key, ty_value) = get_hash_map_element(ty)?;
808    if is_string(ty_key) {
809        Some(ty_value)
810    } else {
811        None
812    }
813}
814
815fn is_bool(ty: &Type) -> bool {
816    is_type(ty, NS_PRIMITIVE, "bool")
817}
818fn is_flag(ty: &Type) -> bool {
819    is_type(ty, NS_STRUCTMETA, "Flag")
820}
821fn is_string(ty: &Type) -> bool {
822    is_type(ty, &[&["std", "string"], &["alloc", "string"]], "String")
823}
824
825fn get_element<'a>(ty: &'a Type, ns: &[&[&str]], name: &str) -> Option<&'a Type> {
826    if let PathArguments::AngleBracketed(args) = get_arguments_of(ty, ns, name)? {
827        if args.args.len() == 1 {
828            if let GenericArgument::Type(ty) = &args.args[0] {
829                return Some(ty);
830            }
831        }
832    }
833    None
834}
835fn get_element2<'a>(ty: &'a Type, ns: &[&[&str]], name: &str) -> Option<(&'a Type, &'a Type)> {
836    if let PathArguments::AngleBracketed(args) = get_arguments_of(ty, ns, name)? {
837        if args.args.len() == 2 {
838            if let (GenericArgument::Type(ty0), GenericArgument::Type(ty1)) =
839                (&args.args[0], &args.args[1])
840            {
841                return Some((ty0, ty1));
842            }
843        }
844    }
845    None
846}
847
848const NS_STRUCTMETA: &[&[&str]] = &[&["structmeta"]];
849const NS_PRIMITIVE: &[&[&str]] = &[&["std", "primitive"], &["core", "primitive"]];
850
851#[cfg(test)]
852mod tests {
853    use super::*;
854    #[test]
855    fn test_is_option() {
856        assert_eq!(
857            get_option_element(&parse_quote!(Option<u8>)),
858            Some(&parse_quote!(u8))
859        );
860    }
861    #[test]
862    fn test_is_option_mod() {
863        assert_eq!(
864            get_option_element(&parse_quote!(option::Option<u8>)),
865            Some(&parse_quote!(u8))
866        );
867    }
868    #[test]
869    fn test_is_option_core() {
870        assert_eq!(
871            get_option_element(&parse_quote!(core::option::Option<u8>)),
872            Some(&parse_quote!(u8))
873        );
874    }
875    #[test]
876    fn test_is_option_std() {
877        assert_eq!(
878            get_option_element(&parse_quote!(std::option::Option<u8>)),
879            Some(&parse_quote!(u8))
880        );
881    }
882}