from_bytes_derive/
lib.rs

1extern crate proc_macro;
2
3use crate::proc_macro::TokenStream;
4use quote::{quote, quote_spanned};
5use syn::spanned::Spanned;
6use syn::{Data, DeriveInput, Fields, Index};
7use std::mem::size_of;
8use syn;
9
10
11#[proc_macro_derive(StructFromBytes)]
12pub fn from_bytes_derive(input: TokenStream) -> TokenStream {
13    let ast = syn::parse(input).unwrap();
14    impl_from_bytes(&ast)
15}
16
17fn impl_from_bytes(ast: &syn::DeriveInput) -> TokenStream {
18    let name = &ast.ident;
19    let gen = quote! {
20        impl StructFromBytes for #name {
21            fn from_bytes(slice: &[u8], offset: usize) -> std::io::Result<Box<Self>> {
22                let size = Self::packed_size();
23                match Self::unpack_from_slice(&slice[offset..offset+size]) {
24                    Ok(v)    => Ok(Box::new(v)),
25                    Err(why) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{:?}", why)))
26                }
27            }
28
29            fn from_stream<R>(stream: &mut R) -> std::io::Result<Box<Self>> where R: Read {
30                let size = Self::packed_size();
31                let mut buffer = vec![0; size];
32                stream.read_exact(&mut buffer)?;
33                match Self::unpack_from_slice(&buffer[..]) {
34                    Ok(v)    => Ok(Box::new(v)),
35                    Err(why) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{:?}", why)))
36                }
37            }
38        }
39    };
40    gen.into()
41}
42
43
44#[proc_macro_derive(PackedSize_u8)]
45pub fn packed_size_derive_u8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
46    static_packed_size(size_of::<u8>(), input)
47}
48
49#[proc_macro_derive(PackedSize_u16)]
50pub fn packed_size_derive_u16(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
51    static_packed_size(size_of::<u16>(), input)
52}
53
54#[proc_macro_derive(PackedSize_u32)]
55pub fn packed_size_derive_u32(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
56    static_packed_size(size_of::<u32>(), input)
57}
58
59#[proc_macro_derive(PackedSize_u64)]
60pub fn packed_size_derive_u64(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
61    static_packed_size(size_of::<u64>(), input)
62}
63
64#[proc_macro_derive(PackedSize_u128)]
65pub fn packed_size_derive_u128(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
66    static_packed_size(size_of::<u128>(), input)
67}
68
69
70#[proc_macro_derive(PackedSize_i8)]
71pub fn packed_size_derive_i8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
72    static_packed_size(size_of::<i8>(), input)
73}
74
75#[proc_macro_derive(PackedSize_i16)]
76pub fn packed_size_derive_i16(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
77    static_packed_size(size_of::<i16>(), input)
78}
79
80#[proc_macro_derive(PackedSize_i32)]
81pub fn packed_size_derive_i32(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
82    static_packed_size(size_of::<i32>(), input)
83}
84
85#[proc_macro_derive(PackedSize_i64)]
86pub fn packed_size_derive_i64(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
87    static_packed_size(size_of::<i64>(), input)
88}
89
90#[proc_macro_derive(PackedSize_i128)]
91pub fn packed_size_derive_i128(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
92    static_packed_size(size_of::<i128>(), input)
93}
94
95fn static_packed_size(size: usize, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
96    let ast: DeriveInput = syn::parse(input).unwrap();
97    let name = &ast.ident;
98    let expanded = quote! {
99        impl PackedSize for #name {
100            fn packed_size() -> usize {
101                #size
102            }
103        }
104    };
105    expanded.into()
106}
107
108#[proc_macro_derive(PackedSize)]
109pub fn packed_size_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
110    let ast: DeriveInput = syn::parse(input).unwrap();
111    let name = &ast.ident;
112    let sum = packed_bytes_sum(&ast.data);
113
114    //println!("{}", sum);
115
116    let expanded = quote! {
117        impl PackedSize for #name {
118            fn packed_size() -> usize {
119                #sum
120            }
121        }
122    };
123    expanded.into()
124}
125
126fn packed_bytes_sum(data: &Data) -> proc_macro2::TokenStream {
127    match *data {
128        Data::Struct(ref data) => {
129            match data.fields {
130                Fields::Named(ref fields) => {
131                    let recurse = fields.named.iter().map(|f| {
132                        let name = &f.ty;
133                        quote_spanned! {f.span() =>
134                            <#name>::packed_size()
135                        }
136                    });
137                    quote! {
138                        0 #(+ #recurse)*
139                    }
140                }
141                Fields::Unnamed(ref fields) => {
142                    let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
143                        let index = Index::from(i);
144                        quote_spanned! {f.span()=>
145                            &self.#index::PackedSize::packed_size()
146                        }
147                    });
148                    quote! {
149                        0 #(+ #recurse)*
150                    }
151                }
152                Fields::Unit => {
153                    quote!(0)
154                }
155            }
156        }
157        Data::Enum(_) | Data::Union(_) => unimplemented!(),
158    }
159}