strum_macros/macros/strings/
as_ref_str.rs1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{parse_quote, Data, DeriveInput, Fields};
4
5use crate::helpers::{
6 non_enum_error, non_single_field_variant_error, HasStrumVariantProperties, HasTypeProperties,
7};
8
9fn get_arms<F>(ast: &DeriveInput, transparent_fn: F) -> syn::Result<Vec<TokenStream>>
10where
11 F: Fn(&TokenStream) -> TokenStream,
12{
13 let name = &ast.ident;
14 let mut arms = Vec::new();
15 let variants = match &ast.data {
16 Data::Enum(v) => &v.variants,
17 _ => return Err(non_enum_error()),
18 };
19
20 let type_properties = ast.get_type_properties()?;
21
22 for variant in variants {
23 let ident = &variant.ident;
24 let variant_properties = variant.get_variant_properties()?;
25
26 if variant_properties.disabled.is_some() {
27 continue;
28 }
29
30 if let Some(..) = variant_properties.transparent {
31 let arm = super::extract_single_field_variant_and_then(name, variant, |tok| {
32 transparent_fn(tok)
33 })
34 .map_err(|_| non_single_field_variant_error("transparent"))?;
35
36 arms.push(arm);
37 continue;
38 }
39
40 let output = variant_properties.get_preferred_name(
44 type_properties.case_style,
45 type_properties.prefix.as_ref(),
46 type_properties.suffix.as_ref(),
47 );
48 let params = match variant.fields {
49 Fields::Unit => quote! {},
50 Fields::Unnamed(..) => quote! { (..) },
51 Fields::Named(..) => quote! { {..} },
52 };
53
54 arms.push(quote! { #name::#ident #params => #output });
55 }
56
57 if arms.len() < variants.len() {
58 arms.push(quote! {
59 _ => panic!(
60 "AsRef::<str>::as_ref() or AsStaticRef::<str>::as_static() \
61 called on disabled variant.",
62 )
63 });
64 }
65
66 Ok(arms)
67}
68
69pub fn as_ref_str_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
70 let name = &ast.ident;
71 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
72 let arms = get_arms(ast, |tok| {
73 quote! { ::core::convert::AsRef::<str>::as_ref(#tok) }
74 })?;
75
76 Ok(quote! {
77 #[automatically_derived]
78 impl #impl_generics ::core::convert::AsRef<str> for #name #ty_generics #where_clause {
79 #[inline]
80 fn as_ref(&self) -> &str {
81 match *self {
82 #(#arms),*
83 }
84 }
85 }
86 })
87}
88
89pub enum GenerateTraitVariant {
90 AsStaticStr,
91 From,
92}
93
94pub fn as_static_str_inner(
95 ast: &DeriveInput,
96 trait_variant: &GenerateTraitVariant,
97) -> syn::Result<TokenStream> {
98 let name = &ast.ident;
99 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
100 let arms = &get_arms(ast, |tok| {
101 quote! { ::core::convert::From::from(#tok) }
102 })?;
103
104 let type_properties = ast.get_type_properties()?;
105 let strum_module_path = type_properties.crate_module_path();
106
107 let mut generics = ast.generics.clone();
108 generics
109 .params
110 .push(syn::GenericParam::Lifetime(syn::LifetimeParam::new(
111 parse_quote!('_derivative_strum),
112 )));
113 let (impl_generics2, _, _) = generics.split_for_impl();
114
115 Ok(match trait_variant {
116 GenerateTraitVariant::AsStaticStr => quote! {
117 #[automatically_derived]
118 impl #impl_generics #strum_module_path::AsStaticRef<str> for #name #ty_generics #where_clause {
119 #[inline]
120 fn as_static(&self) -> &'static str {
121 match *self {
122 #(#arms),*
123 }
124 }
125 }
126 },
127 GenerateTraitVariant::From if !type_properties.const_into_str => quote! {
128 #[automatically_derived]
129 impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause {
130 #[inline]
131 fn from(x: #name #ty_generics) -> &'static str {
132 match x {
133 #(#arms),*
134 }
135 }
136 }
137 #[automatically_derived]
138 impl #impl_generics2 ::core::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause {
139 #[inline]
140 fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
141 match *x {
142 #(#arms),*
143 }
144 }
145 }
146 },
147 GenerateTraitVariant::From => quote! {
148 #[automatically_derived]
149 impl #impl_generics #name #ty_generics #where_clause {
150 pub const fn into_str(&self) -> &'static str {
151 match self {
152 #(#arms),*
153 }
154 }
155 }
156 #[automatically_derived]
157 impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause {
158 fn from(x: #name #ty_generics) -> &'static str {
159 match x {
160 #(#arms),*
161 }
162 }
163 }
164 #[automatically_derived]
165 impl #impl_generics2 ::core::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause {
166 fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
167 x.into_str()
168 }
169 }
170 },
171 })
172}