strum_macros/macros/
enum_try_as.rs

1use crate::helpers::{non_enum_error, snakify, HasStrumVariantProperties};
2use proc_macro2::TokenStream;
3use quote::{format_ident, quote, ToTokens};
4use syn::{Data, DeriveInput};
5
6pub 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}