neli_proc_macros/
neli_enum.rs
1use proc_macro::TokenStream;
2use proc_macro2::{Span, TokenStream as TokenStream2};
3use quote::quote;
4use syn::{
5 parse, parse_str, Arm, Attribute, Expr, Ident, ItemEnum, Lit, Meta, Path, Token, Type, Variant,
6};
7
8use crate::shared::remove_bad_attrs;
9
10fn parse_type_attr(attr: Meta) -> Type {
11 if let Meta::NameValue(nv) = attr {
12 if nv.path == parse_str::<Path>("serialized_type").unwrap() {
13 if let Lit::Str(ls) = nv.lit {
14 return parse_str::<Type>(&ls.value())
15 .unwrap_or_else(|_| panic!("Invalid type supplied: {}", ls.value()));
16 }
17 }
18 }
19
20 panic!("Attribute in the form #[neli(serialized_type = \"TYPE_LITERAL_STR\")] required")
21}
22
23fn parse_enum(enm: &mut ItemEnum, ty: &Type) -> Vec<(Vec<Attribute>, Ident, Expr)> {
24 let exprs = enm
25 .variants
26 .iter_mut()
27 .map(|var| {
28 if let Some((_, expr)) = var.discriminant.take() {
29 (var.attrs.clone(), var.ident.clone(), expr)
30 } else {
31 panic!("All variants in the provided enum require an expression assignment")
32 }
33 })
34 .collect();
35 if !enm.variants.trailing_punct() {
36 enm.variants.push_punct(Token));
37 }
38 enm.variants.push_value(
39 parse::<Variant>(TokenStream::from(quote! {
40 UnrecognizedConst(#ty)
41 }))
42 .expect("Could not parse tokens as a variant"),
43 );
44 exprs
45}
46
47fn parse_from_info(
48 enum_name: Ident,
49 var_info: Vec<(Vec<Attribute>, Ident, Expr)>,
50) -> (Vec<Arm>, Vec<Arm>) {
51 let mut from_const_info = Vec::new();
52 let mut from_type_info = Vec::new();
53 for (mut attributes, ident, expr) in var_info {
54 attributes = remove_bad_attrs(attributes);
55 let mut from_const_arm = parse::<Arm>(TokenStream::from(quote! {
56 #(
57 #attributes
58 )*
59 i if i == #expr => #enum_name::#ident,
60 }))
61 .expect("Failed to parse tokens as a match arm");
62 from_const_arm.attrs = attributes.clone();
63 from_const_info.push(from_const_arm);
64
65 let mut from_type_arm = parse::<Arm>(TokenStream::from(quote! {
66 #(
67 #attributes
68 )*
69 #enum_name::#ident => #expr,
70 }))
71 .expect("Failed to parse tokens as a match arm");
72 from_type_arm.attrs = attributes.clone();
73 from_type_info.push(from_type_arm);
74 }
75 (from_const_info, from_type_info)
76}
77
78pub fn generate_neli_enum(mut enm: ItemEnum, meta: Meta) -> TokenStream2 {
79 let enum_name = enm.ident.clone();
80 let ty = parse_type_attr(meta);
81
82 let variant_info = parse_enum(&mut enm, &ty);
83 let (from_const_info, from_type_info) = parse_from_info(enum_name.clone(), variant_info);
84
85 quote! {
86 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
87 #[allow(missing_docs)]
88 #enm
89
90 impl #enum_name {
91 pub fn is_unrecognized(&self) -> bool {
95 match *self {
96 #enum_name::UnrecognizedConst(_) => true,
97 _ => false,
98 }
99 }
100 }
101
102 impl neli::Size for #enum_name {
103 fn unpadded_size(&self) -> usize {
104 std::mem::size_of::<#ty>()
105 }
106 }
107
108 impl neli::TypeSize for #enum_name {
109 fn type_size() -> usize {
110 std::mem::size_of::<#ty>()
111 }
112 }
113
114 impl neli::ToBytes for #enum_name {
115 fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), neli::err::SerError> {
116 let bin_rep: #ty = self.into();
117 bin_rep.to_bytes(buffer)
118 }
119 }
120
121 impl<'lt> neli::FromBytes<'lt> for #enum_name {
122 fn from_bytes(buffer: &mut std::io::Cursor<&'lt [u8]>) -> Result<Self, neli::err::DeError> {
123 Ok(#enum_name::from(<#ty as neli::FromBytes>::from_bytes(
124 buffer
125 )?))
126 }
127 }
128
129 impl From<#ty> for #enum_name {
130 fn from(cnst: #ty) -> Self {
131 match cnst {
132 #(
133 #from_const_info
134 )*
135 i => #enum_name::UnrecognizedConst(i),
136 }
137 }
138 }
139
140 impl From<#enum_name> for #ty {
141 fn from(enm: #enum_name) -> Self {
142 match enm {
143 #(
144 #from_type_info
145 )*
146 #enum_name::UnrecognizedConst(i) => i,
147 }
148 }
149 }
150
151 impl From<&#enum_name> for #ty {
152 fn from(enm: &#enum_name) -> Self {
153 match *enm {
154 #(
155 #from_type_info
156 )*
157 #enum_name::UnrecognizedConst(i) => i,
158 }
159 }
160 }
161 }
162}