struct_deser_derive/
lib.rs1extern crate proc_macro;
4extern crate syn;
5#[macro_use]
6extern crate quote;
7
8use proc_macro::TokenStream;
9use quote::{Tokens, ToTokens};
10
11#[proc_macro_derive(StructDeser, attributes(struct_deser, be, le))]
12pub fn derive_struct_deser(input: TokenStream) -> TokenStream {
13 let s = input.to_string();
14 let ast = syn::parse_derive_input(&s).unwrap();
15
16 let gen = impl_struct_deser(&ast);
17
18 gen.parse().unwrap()
19}
20
21#[derive(Eq, PartialEq)]
23enum ByteOrder {
24 LE,
25 BE,
26}
27
28impl ToTokens for ByteOrder {
29 fn to_tokens(&self, tokens: &mut Tokens) {
30 match *self {
31 ByteOrder::LE => tokens.append("LE"),
32 ByteOrder::BE => tokens.append("BE"),
33 }
34 }
35}
36
37fn impl_struct_deser(ast: &syn::DeriveInput) -> quote::Tokens {
39 use syn::{Body, VariantData};
40 use quote::Ident;
41
42 let mut res = quote::Tokens::new();
43 let body = if let Body::Struct(ref body) = ast.body {
44 body
45 } else {
46 panic!("The type must be a struct");
47 };
48
49 impl_identifier(ast, &mut res);
50
51 let name = &ast.ident;
52 let dummy_const = Ident::new(format!("_IMPL_STRUCT_DESER_FOR_{}", name));
53
54 let mut deser_body = quote::Tokens::new();
55 let mut ser_body = quote::Tokens::new();
56 let mut byte_len = quote! { 0 };
57 for (field_no, field) in body.fields().iter().enumerate() {
58 let ty = &field.ty;
59
60 let byte_order = get_byte_order(&field.attrs);
61
62 let field_accessor = match field.ident {
63 Some(ref ident) => quote! { #ident },
64 None => {
65 let mut tmp = Tokens::new();
67 tmp.append(format!("{}", field_no));
68 tmp
69 },
70 };
71
72 let byte_slice = quote! { bytes[(#byte_len)..(#byte_len + <#ty as _struct_deser::SerializedByteLen>::BYTE_LEN)] };
73
74 let (deser_impl, ser_impl) = match byte_order {
75 None => (quote! { _struct_deser::FromBytes::from_bytes(&#byte_slice) },
76 quote! { _struct_deser::IntoBytes::into_bytes(&self.#field_accessor, &mut #byte_slice); }),
77 Some(bo) => (quote! { _struct_deser::FromBytesOrdered::from_bytes::<_struct_deser::byteorder::#bo>(&#byte_slice) },
78 quote! { _struct_deser::IntoBytesOrdered::into_bytes::<_struct_deser::byteorder::#bo>(&self.#field_accessor, &mut #byte_slice); }),
79 };
80
81 deser_body.append(match field.ident {
82 Some(ref ident) => quote! { #ident: #deser_impl, },
83 None => quote! { #deser_impl, },
84 });
85 ser_body.append(ser_impl);
86
87 byte_len.append(quote! { + <#ty as _struct_deser::SerializedByteLen>::BYTE_LEN });
88 }
89
90 match *body {
91 VariantData::Struct(_) => res.append(quote! {
92 impl _struct_deser::FromBytes for #name {
93 fn from_bytes(bytes: &[u8]) -> Self {
94 assert_eq!(bytes.len(), <Self as _struct_deser::SerializedByteLen>::BYTE_LEN);
95
96 #name {
97 #deser_body
98 }
99 }
100 }
101 }),
102 VariantData::Tuple(_) => res.append(quote! {
103 impl _struct_deser::FromBytes for #name {
104 fn from_bytes(bytes: &[u8]) -> Self {
105 assert_eq!(bytes.len(), <Self as _struct_deser::SerializedByteLen>::BYTE_LEN);
106
107 #name(#deser_body)
108 }
109 }
110 }),
111 VariantData::Unit => panic!("(De)serializing empty struct doesn't make sense"),
112 }
113
114 res.append(quote! {
115 impl _struct_deser::IntoBytes for #name {
116 fn into_bytes(&self, bytes: &mut [u8]) {
117 assert_eq!(bytes.len(), <Self as _struct_deser::SerializedByteLen>::BYTE_LEN);
118 #ser_body
119 }
120 }
121
122 impl _struct_deser::SerializedByteLen for #name {
123 const BYTE_LEN: usize = #byte_len;
124 }
125 });
126
127 res = quote! {
128 #[allow(non_upper_case_globals)]
129 const #dummy_const: () = {
130 extern crate struct_deser as _struct_deser;
131 #res
132 };
133 };
134
135 res
141}
142
143fn impl_identifier(ast: &syn::DeriveInput, res: &mut Tokens) {
145 use syn::{MetaItem, NestedMetaItem, Lit};
146
147 let name = &ast.ident;
148
149 for attr in &ast.attrs {
150 if attr.value.name() == "struct_deser" {
151 if let MetaItem::List(_, ref nested) = attr.value {
152 let mut val = None;
153 let mut ty = None;
154 for item in nested {
155 if let NestedMetaItem::MetaItem(MetaItem::NameValue(ref name, ref value)) = *item {
156 if name == "identifier" {
157 val = Some(value);
158 }
159
160 if name == "identifier_type" {
161 ty = Some(value);
162 }
163 }
164 }
165
166 match (val, ty) {
167 (Some(&Lit::Str(ref val, _)), Some(&Lit::Str(ref ty, _))) => {
168 let ty = syn::parse_type(ty).expect("expected type");
169 let val = syn::parse_expr(val).expect("expected expression");
170
171 res.append(quote! {
172 impl _struct_deser::Identifier for #name {
173 type IdentifierType = #ty;
174 const IDENTIFIER: Self::IdentifierType = #val;
175 }
176 });
177 return;
178 },
179 (None, None) => (),
180 (Some(_), Some(_)) => panic!("Identifier and it's type must be inside string"),
181 _ => panic!("Both identifier and type must be specified or none of them"),
182 }
183 }
184 }
185 }
186}
187
188fn get_byte_order(attrs: &[syn::Attribute]) -> Option<ByteOrder> {
190 use syn::MetaItem;
191
192 let mut byte_order = None;
193 for attr in attrs {
194 if let MetaItem::Word(ref word) = attr.value {
195 if word.as_ref() == "be" {
196 byte_order = Some(ByteOrder::BE);
197 if byte_order == Some(ByteOrder::LE) {
198 panic!("Conflicting byte order: you can't specify both Little and Big endian");
199 }
200 }
201
202 if word.as_ref() == "le" {
203 byte_order = Some(ByteOrder::LE);
204 if byte_order == Some(ByteOrder::BE) {
205 panic!("Conflicting byte order: you can't specify both Little and Big endian");
206 }
207 }
208 }
209 }
210
211 byte_order
212}