]> git.proxmox.com Git - rustc.git/blob - vendor/strum_macros/src/macros/strings/as_ref_str.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / vendor / strum_macros / src / macros / strings / as_ref_str.rs
1 use proc_macro2::TokenStream;
2 use syn;
3
4 use crate::helpers::case_style::CaseStyle;
5 use helpers::{extract_meta, CaseStyleHelpers, MetaIteratorHelpers};
6
7 fn get_arms(ast: &syn::DeriveInput) -> Vec<TokenStream> {
8 let name = &ast.ident;
9 let mut arms = Vec::new();
10 let variants = match ast.data {
11 syn::Data::Enum(ref v) => &v.variants,
12 _ => panic!("This macro only works on Enums"),
13 };
14
15 let type_meta = extract_meta(&ast.attrs);
16 let case_style = type_meta
17 .find_unique_property("strum", "serialize_all")
18 .map(|style| CaseStyle::from(style.as_ref()));
19
20 for variant in variants {
21 use syn::Fields::*;
22 let ident = &variant.ident;
23 let meta = extract_meta(&variant.attrs);
24
25 if meta.is_disabled() {
26 continue;
27 }
28
29 // Look at all the serialize attributes.
30 // Use `to_string` attribute (not `as_ref_str` or something) to keep things consistent
31 // (i.e. always `enum.as_ref().to_string() == enum.to_string()`).
32 let output = if let Some(n) = meta.find_unique_property("strum", "to_string") {
33 n
34 } else {
35 let mut attrs = meta.find_properties("strum", "serialize");
36 // We always take the longest one. This is arbitary, but is *mostly* deterministic
37 attrs.sort_by_key(|s| s.len());
38 if let Some(n) = attrs.pop() {
39 n
40 } else {
41 ident.convert_case(case_style)
42 }
43 };
44
45 let params = match variant.fields {
46 Unit => quote! {},
47 Unnamed(..) => quote! { (..) },
48 Named(..) => quote! { {..} },
49 };
50
51 arms.push(quote! { #name::#ident #params => #output });
52 }
53
54 if arms.len() < variants.len() {
55 arms.push(quote! {
56 _ => panic!("AsRef::<str>::as_ref() or AsStaticRef::<str>::as_static() \
57 called on disabled variant.")
58 })
59 }
60
61 arms
62 }
63
64 pub fn as_ref_str_inner(ast: &syn::DeriveInput) -> TokenStream {
65 let name = &ast.ident;
66 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
67 let arms = get_arms(ast);
68 quote! {
69 impl #impl_generics ::std::convert::AsRef<str> for #name #ty_generics #where_clause {
70 fn as_ref(&self) -> &str {
71 match *self {
72 #(#arms),*
73 }
74 }
75 }
76 }
77 }
78
79 pub enum GenerateTraitVariant {
80 AsStaticStr,
81 From,
82 }
83
84 pub fn as_static_str_inner(
85 ast: &syn::DeriveInput,
86 trait_variant: GenerateTraitVariant,
87 ) -> TokenStream {
88 let name = &ast.ident;
89 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
90 let arms = get_arms(ast);
91
92 let mut generics = ast.generics.clone();
93 generics
94 .params
95 .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(
96 parse_quote!('_derivative_strum),
97 )));
98 let (impl_generics2, _, _) = generics.split_for_impl();
99 let arms2 = arms.clone();
100 let arms3 = arms.clone();
101 match trait_variant {
102 GenerateTraitVariant::AsStaticStr => {
103 quote! {
104 impl #impl_generics ::strum::AsStaticRef<str> for #name #ty_generics #where_clause {
105 fn as_static(&self) -> &'static str {
106 match *self {
107 #(#arms),*
108 }
109 }
110 }
111 }
112 }
113 GenerateTraitVariant::From => {
114 quote! {
115 impl #impl_generics ::std::convert::From<#name #ty_generics> for &'static str #where_clause {
116 fn from(x: #name #ty_generics) -> &'static str {
117 match x {
118 #(#arms2),*
119 }
120 }
121 }
122 impl #impl_generics2 ::std::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause {
123 fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
124 match *x {
125 #(#arms3),*
126 }
127 }
128 }
129 }
130 }
131 }
132 }