• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::helpers::{case_style::snakify, non_enum_error, HasStrumVariantProperties};
2 use proc_macro2::TokenStream;
3 use quote::{format_ident, quote, ToTokens};
4 use syn::{Data, DeriveInput};
5 
enum_try_as_inner(ast: &DeriveInput) -> syn::Result<TokenStream>6 pub fn enum_try_as_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
7     let variants = match &ast.data {
8         Data::Enum(v) => &v.variants,
9         _ => return Err(non_enum_error()),
10     };
11 
12     let enum_name = &ast.ident;
13     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
14 
15     let variants: Vec<_> = variants
16         .iter()
17         .filter_map(|variant| {
18             if variant.get_variant_properties().ok()?.disabled.is_some() {
19                 return None;
20             }
21 
22             match &variant.fields {
23                 syn::Fields::Unnamed(values) => {
24                     let variant_name = &variant.ident;
25                     let types: Vec<_> = values.unnamed.iter().map(|field| {
26                         field.ty.to_token_stream()
27                     }).collect();
28                     let field_names: Vec<_> = values.unnamed.iter().enumerate().map(|(i, _)| {
29                         let name = "x".repeat(i + 1);
30                         let name = format_ident!("{}", name);
31                         quote! {#name}
32                     }).collect();
33 
34                     let move_fn_name = format_ident!("try_as_{}", snakify(&variant_name.to_string()));
35                     let ref_fn_name = format_ident!("try_as_{}_ref", snakify(&variant_name.to_string()));
36                     let mut_fn_name = format_ident!("try_as_{}_mut", snakify(&variant_name.to_string()));
37 
38                     Some(quote! {
39                         #[must_use]
40                         #[inline]
41                         pub fn #move_fn_name(self) -> ::core::option::Option<(#(#types),*)> {
42                             match self {
43                                 #enum_name::#variant_name (#(#field_names),*) => Some((#(#field_names),*)),
44                                 _ => None
45                             }
46                         }
47 
48                         #[must_use]
49                         #[inline]
50                         pub const fn #ref_fn_name(&self) -> ::core::option::Option<(#(&#types),*)> {
51                             match self {
52                                 #enum_name::#variant_name (#(#field_names),*) => Some((#(#field_names),*)),
53                                 _ => None
54                             }
55                         }
56 
57                         #[must_use]
58                         #[inline]
59                         pub fn #mut_fn_name(&mut self) -> ::core::option::Option<(#(&mut #types),*)> {
60                             match self {
61                                 #enum_name::#variant_name (#(#field_names),*) => Some((#(#field_names),*)),
62                                 _ => None
63                             }
64                         }
65                     })
66                 },
67                 _ => {
68                     return None;
69                 }
70             }
71 
72         })
73         .collect();
74 
75     Ok(quote! {
76         impl #impl_generics #enum_name #ty_generics #where_clause {
77             #(#variants)*
78         }
79     })
80 }
81