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