Skip to main content

struct_deser_derive/
lib.rs

1//! Derive proc macro for `struct_deser` crate. See that one for more information.
2
3extern 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// Not to be confused  with one in byteorder crate...
22#[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
37// Actual implementation
38fn 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                // Interpolating directly would cause adding `usize` sufix
66                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    /*
136    if name == "IntegersTuple" {
137        panic!(res.to_string());
138    }
139    */
140    res
141}
142
143// Impls identifier trait
144fn 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
188// Scans attributes for byte order
189fn 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}