ruma_macros/serde/
enum_as_ref_str.rs

1use proc_macro2::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{Fields, FieldsNamed, FieldsUnnamed, ItemEnum};
4
5use super::{
6    attr::EnumAttrs,
7    util::{get_enum_attributes, get_rename_rule},
8};
9
10pub fn expand_enum_as_ref_str(input: &ItemEnum) -> syn::Result<TokenStream> {
11    let enum_name = &input.ident;
12    let rename_rule = get_rename_rule(input)?;
13    let branches: Vec<_> = input
14        .variants
15        .iter()
16        .map(|v| {
17            let variant_name = &v.ident;
18            let EnumAttrs { rename, .. } = get_enum_attributes(v)?;
19            let (field_capture, variant_str) = match (rename, &v.fields) {
20                (None, Fields::Unit) => (
21                    None,
22                    rename_rule.apply_to_variant(&variant_name.to_string()).into_token_stream(),
23                ),
24                (Some(rename), Fields::Unit) => (None, rename.into_token_stream()),
25                (None, Fields::Named(FieldsNamed { named: fields, .. }))
26                | (None, Fields::Unnamed(FieldsUnnamed { unnamed: fields, .. })) => {
27                    if fields.len() != 1 {
28                        return Err(syn::Error::new_spanned(
29                            v,
30                            "multiple data fields are not supported",
31                        ));
32                    }
33
34                    let capture = match &fields[0].ident {
35                        Some(name) => quote! { { #name: inner } },
36                        None => quote! { (inner) },
37                    };
38
39                    (Some(capture), quote! { &inner.0 })
40                }
41                (Some(_), _) => {
42                    return Err(syn::Error::new_spanned(
43                        v,
44                        "ruma_enum(rename) is only allowed on unit variants",
45                    ));
46                }
47            };
48
49            Ok(quote! {
50                #enum_name :: #variant_name #field_capture => #variant_str
51            })
52        })
53        .collect::<syn::Result<_>>()?;
54
55    Ok(quote! {
56        #[automatically_derived]
57        #[allow(deprecated)]
58        impl ::std::convert::AsRef<::std::primitive::str> for #enum_name {
59            fn as_ref(&self) -> &::std::primitive::str {
60                match self { #(#branches),* }
61            }
62        }
63    })
64}