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 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}