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!(::syn::parse::Parse),
28 &[],
29 quote! {
30 fn parse(input: ::syn::parse::ParseStream<'_>) -> ::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(::syn::Error::new(input.span(), #msg));
119 }
120 input.parse::<::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::<::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(::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(|| ::syn::Error::new(::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(|| ::syn::Error::new(::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(::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 },
638 NameArgs {
639 ty: &'a Type,
640 is_option: bool,
641 is_vec: bool,
642 },
643}
644
645impl<'a> NamedParamType<'a> {
646 fn from_type(ty: &'a Type, may_flag: bool) -> Self {
647 if may_flag && is_bool(ty) {
648 Self::Bool
649 } else if may_flag && is_flag(ty) {
650 Self::Flag
651 } else if let Some(ty) = get_name_value_element(ty) {
652 Self::NameValue { ty }
653 } else if let Some(mut ty) = get_name_args_element(ty) {
654 let mut is_option = false;
655 if let Some(e) = get_option_element(ty) {
656 is_option = true;
657 ty = e;
658 }
659 let mut is_vec = false;
660 if let Some(e) = get_vec_element(ty) {
661 is_vec = true;
662 ty = e;
663 }
664 Self::NameArgs {
665 ty,
666 is_option,
667 is_vec,
668 }
669 } else {
670 let mut ty = ty;
671 let mut is_vec = false;
672 if let Some(e) = get_vec_element(ty) {
673 is_vec = true;
674 ty = e;
675 }
676 Self::Value { ty, is_vec }
677 }
678 }
679 fn is_flag(&self) -> bool {
680 match self {
681 NamedParamType::Bool | NamedParamType::Flag => true,
682 NamedParamType::Value { .. } | NamedParamType::NameValue { .. } => false,
683 NamedParamType::NameArgs { is_option, .. } => *is_option,
684 }
685 }
686 fn is_name_value(&self) -> bool {
687 match self {
688 NamedParamType::Bool | NamedParamType::Flag => false,
689 NamedParamType::Value { is_vec, .. } => !is_vec,
690 NamedParamType::NameValue { .. } => true,
691 NamedParamType::NameArgs { .. } => false,
692 }
693 }
694 fn is_name_args(&self) -> bool {
695 match self {
696 NamedParamType::Bool | NamedParamType::Flag => false,
697 NamedParamType::Value { is_vec, .. } => *is_vec,
698 NamedParamType::NameValue { .. } => false,
699 NamedParamType::NameArgs { .. } => true,
700 }
701 }
702 fn build_parse_expr(&self, kind: ArgKind, span: Span) -> TokenStream {
703 match self {
704 NamedParamType::Bool | NamedParamType::Flag => quote!(span),
705 NamedParamType::Value { ty, is_vec } => {
706 if *is_vec {
707 build_parse_expr_name_args(ty, *is_vec, span)
708 } else {
709 build_parse_expr(ty, span)
710 }
711 }
712 NamedParamType::NameValue { ty } => {
713 quote!(::structmeta::NameValue { name_span : span, value: input.parse::<#ty>()? })
714 }
715 NamedParamType::NameArgs {
716 ty,
717 is_option,
718 is_vec,
719 } => {
720 let args = if kind == ArgKind::Flag && *is_option {
721 quote!(None)
722 } else {
723 let args = build_parse_expr_name_args(ty, *is_vec, span);
724 if *is_option {
725 quote!(Some(#args))
726 } else {
727 args
728 }
729 };
730 quote!(structmeta::NameArgs { name_span : span, args: #args })
731 }
732 }
733 }
734}
735
736fn build_parse_expr(ty: &Type, span: Span) -> TokenStream {
737 quote_spanned!(span=> input.parse::<#ty>()?)
738}
739fn build_parse_expr_name_args(ty: &Type, is_vec: bool, span: Span) -> TokenStream {
740 let value = if is_vec {
741 quote_spanned!(span=> ::syn::punctuated::Punctuated::<#ty, ::syn::Token![,]>::parse_terminated(&content)?.into_iter().collect())
742 } else {
743 quote_spanned!(span=> content.parse::<#ty>()?)
744 };
745 quote! {
746 {
747 let content;
748 ::syn::parenthesized!(content in input);
749 #value
750 }
751 }
752}
753
754#[derive(Eq, PartialEq, Debug, Copy, Clone)]
755enum ArgKind {
756 Flag,
757 NameValue,
758 NameArgs,
759}
760impl ArgKind {
761 fn to_helper_name_index_variant(self) -> TokenStream {
762 match self {
763 Self::Flag => quote!(Flag),
764 Self::NameValue => quote!(NameValue),
765 Self::NameArgs => quote!(NameArgs),
766 }
767 }
768}
769
770fn get_option_element(ty: &Type) -> Option<&Type> {
771 get_element(ty, &[&["std", "option"], &["core", "option"]], "Option")
772}
773fn get_vec_element(ty: &Type) -> Option<&Type> {
774 get_element(ty, &[&["std", "vec"], &["alloc", "vec"]], "Vec")
775}
776fn get_name_value_element(ty: &Type) -> Option<&Type> {
777 get_element(ty, NS_STRUCTMETA, "NameValue")
778}
779fn get_name_args_element(ty: &Type) -> Option<&Type> {
780 get_element(ty, NS_STRUCTMETA, "NameArgs")
781}
782fn get_hash_map_element(ty: &Type) -> Option<(&Type, &Type)> {
783 get_element2(
784 ty,
785 &[&["std", "collections"], &["std", "collections", "hash_map"]],
786 "HashMap",
787 )
788}
789fn get_hash_map_string_element(ty: &Type) -> Option<&Type> {
790 let (ty_key, ty_value) = get_hash_map_element(ty)?;
791 if is_string(ty_key) {
792 Some(ty_value)
793 } else {
794 None
795 }
796}
797
798fn is_bool(ty: &Type) -> bool {
799 is_type(ty, NS_PRIMITIVE, "bool")
800}
801fn is_flag(ty: &Type) -> bool {
802 is_type(ty, NS_STRUCTMETA, "Flag")
803}
804fn is_string(ty: &Type) -> bool {
805 is_type(ty, &[&["std", "string"], &["alloc", "string"]], "String")
806}
807
808fn get_element<'a>(ty: &'a Type, ns: &[&[&str]], name: &str) -> Option<&'a Type> {
809 if let PathArguments::AngleBracketed(args) = get_arguments_of(ty, ns, name)? {
810 if args.args.len() == 1 {
811 if let GenericArgument::Type(ty) = &args.args[0] {
812 return Some(ty);
813 }
814 }
815 }
816 None
817}
818fn get_element2<'a>(ty: &'a Type, ns: &[&[&str]], name: &str) -> Option<(&'a Type, &'a Type)> {
819 if let PathArguments::AngleBracketed(args) = get_arguments_of(ty, ns, name)? {
820 if args.args.len() == 2 {
821 if let (GenericArgument::Type(ty0), GenericArgument::Type(ty1)) =
822 (&args.args[0], &args.args[1])
823 {
824 return Some((ty0, ty1));
825 }
826 }
827 }
828 None
829}
830
831const NS_STRUCTMETA: &[&[&str]] = &[&["structmeta"]];
832const NS_PRIMITIVE: &[&[&str]] = &[&["std", "primitive"], &["core", "primitive"]];
833
834#[cfg(test)]
835mod tests {
836 use super::*;
837 #[test]
838 fn test_is_option() {
839 assert_eq!(
840 get_option_element(&parse_quote!(Option<u8>)),
841 Some(&parse_quote!(u8))
842 );
843 }
844 #[test]
845 fn test_is_option_mod() {
846 assert_eq!(
847 get_option_element(&parse_quote!(option::Option<u8>)),
848 Some(&parse_quote!(u8))
849 );
850 }
851 #[test]
852 fn test_is_option_core() {
853 assert_eq!(
854 get_option_element(&parse_quote!(core::option::Option<u8>)),
855 Some(&parse_quote!(u8))
856 );
857 }
858 #[test]
859 fn test_is_option_std() {
860 assert_eq!(
861 get_option_element(&parse_quote!(std::option::Option<u8>)),
862 Some(&parse_quote!(u8))
863 );
864 }
865}