1extern crate proc_macro;
45use proc_macro2::{Delimiter, Span, TokenStream, TokenTree};
46use proc_macro_error::{abort, abort_call_site, proc_macro_error};
47use quote::quote;
48use syn::{parse_macro_input, AttrStyle, Attribute, Data, DeriveInput, Expr, Ident};
49
50#[proc_macro_derive(TryFromReprToEnum)]
51#[proc_macro_error]
52pub fn derive_try_from(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
53 let input = parse_macro_input!(input as DeriveInput);
54 let reprtype = find_repr_type(input.attrs);
55 let enum_name = input.ident;
56
57 let enum_data = get_enum_data(&input.data);
58 let match_expr = match_impl(&enum_name, enum_data);
59
60 proc_macro::TokenStream::from(quote! {
61
62 impl core::convert::TryFrom<#reprtype> for #enum_name {
63 type Error = #reprtype;
64
65 fn try_from(val : #reprtype) -> Result<Self, <Self as core::convert::TryFrom<#reprtype>>::Error> {
66 #match_expr
67 }
68 }
69 })
70}
71
72#[proc_macro_derive(FromEnumToRepr)]
73#[proc_macro_error]
74pub fn derive_into_primitive_and_from_enum(
75 input: proc_macro::TokenStream,
76) -> proc_macro::TokenStream {
77 let input = parse_macro_input!(input as DeriveInput);
78 let reprtype = find_repr_type(input.attrs);
79 let enum_name = input.ident;
80
81 proc_macro::TokenStream::from(quote! {
82
83 impl core::convert::From<#enum_name> for #reprtype {
84 fn from(enum_value : #enum_name) -> Self {
85 enum_value as Self
86 }
87 }
88 })
89}
90
91fn find_repr_type(attrs: Vec<Attribute>) -> Ident {
92 for attr in attrs {
93 match attr.style {
94 AttrStyle::Outer => {
95 if attr.path.is_ident(&Ident::new("repr", Span::call_site())) {
96 let tokens = attr.tokens;
97 let mut repr_tokens_iter = tokens.into_iter();
98 let first_token: TokenTree = repr_tokens_iter.next().unwrap();
99 if repr_tokens_iter.next().is_some() {
100 abort!(
101 first_token.span(),
102 "Repr is malformed, expecting repr(TYPE)"
103 );
104 }
105 let repr_type = match first_token.clone() {
106 TokenTree::Group(repr_items) => {
107 if repr_items.delimiter() != Delimiter::Parenthesis {
108 abort!(repr_items.span(), "Repr is malformed, expecting repr(TYPE)")
109 }
110 let mut repr_types_iter = repr_items.stream().into_iter();
111 let first_repr_item = repr_types_iter.next().unwrap();
112 if let Some(second_repr_type) = repr_types_iter.next() {
114 abort!(
115 second_repr_type.span(),
116 "Many repr types specified. Expecting only one."
117 )
118 }
119 match first_repr_item.clone() {
120 TokenTree::Ident(repr_type) => repr_type,
121 unexpected_type => abort!(
122 first_repr_item.span(),
123 "Unexpected type in repr {}",
124 unexpected_type
125 ),
126 }
127 }
128 unexpected_token => abort!(
129 first_token.span(),
130 "Unexpected token with repr {}",
131 unexpected_token
132 ),
133 };
134 return repr_type;
135 }
136 }
137 _ => {
138 continue;
140 }
141 }
142 }
143 abort_call_site!("Repr not found");
144}
145
146fn get_enum_data(data: &Data) -> Vec<(Ident, Expr)> {
147 let mut enum_data: Vec<(Ident, Expr)> = Vec::new();
148 match *data {
149 Data::Enum(ref data) => {
150 for variant in data.variants.iter() {
151 let pair = variant.discriminant.as_ref().unwrap();
152 let expr = pair.1.clone();
153 enum_data.push((variant.ident.clone(), expr));
154 }
155 }
156 Data::Struct(_) | Data::Union(_) => {
157 abort_call_site!("Unexpected type! Use derive with enums only")
158 }
159 }
160 enum_data
161}
162
163fn match_impl(enum_name: &Ident, enum_data: Vec<(Ident, Expr)>) -> TokenStream {
164 let mut match_arms = TokenStream::new();
165 for (id, expr) in enum_data {
166 match_arms.extend(quote! { #expr => Ok(#enum_name::#id),});
167 }
168 match_arms.extend(quote! { unexpected => Err(unexpected) });
169 quote! {
170 match val {
171 #match_arms
172 }
173 }
174}