1#![recursion_limit = "128"]
2
3extern crate proc_macro;
12extern crate syn;
13#[macro_use]
14extern crate quote;
15
16use proc_macro::TokenStream;
17use syn::Data;
18use quote::{Tokens, ToTokens};
19
20#[proc_macro_derive(Serializable)]
22pub fn npy_data(input: TokenStream) -> TokenStream {
23 let ast = syn::parse(input).unwrap();
28
29 let expanded = impl_npy_data(&ast);
31
32 expanded.into()
34}
35
36fn impl_npy_data(ast: &syn::DeriveInput) -> quote::Tokens {
37 let name = &ast.ident;
38 let fields = match ast.data {
39 Data::Struct(ref data) => &data.fields,
40 _ => panic!("#[derive(Serializable)] can only be used with structs"),
41 };
42 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
44
45 let idents = fields.iter().map(|f| {
46 let mut t = Tokens::new();
47 f.ident.clone().expect("Tuple structs not supported").to_tokens(&mut t);
48 t
49 }).collect::<Vec<_>>();
50 let types = fields.iter().map(|f| {
51 let mut t = Tokens::new();
52 f.ty.to_tokens(&mut t);
53 t
54 }).collect::<Vec<_>>();
55
56 let idents_c = idents.clone();
57 let idents_str = idents.clone().into_iter().map(|t| t.to_string()).collect::<Vec<_>>();
58 let idents_str_c1 = idents_str.clone();
59 let types_c1 = types.clone();
60 let types_c2 = types.clone();
61 let types_c3 = types.clone();
62
63 let nats_0 = 0usize..;
64 let nats_1 = 0usize..;
65 let n_fields = types.len();
66
67 quote! {
68 impl #impl_generics ::npy::Serializable for #name #ty_generics #where_clause {
69 fn dtype() -> ::npy::DType {
70 ::npy::DType::Record(vec![#(
71 ::npy::Field {
72 name: #idents_str_c1.to_string(),
73 dtype: <#types_c1 as ::npy::Serializable>::dtype()
74 }
75 ),*])
76 }
77
78 fn n_bytes() -> usize {
79 #( <#types_c2 as ::npy::Serializable>::n_bytes() )+*
80 }
81
82 #[allow(unused_assignments)]
83 fn read(buf: &[u8]) -> Self {
84 let mut offset = 0;
85 let mut offsets = [0; #n_fields + 1];
86 #(
87 offset += <#types_c3 as ::npy::Serializable>::n_bytes();
88 offsets[#nats_0 + 1] = offset;
89 )*
90
91 #name { #(
92 #idents: ::npy::Serializable::read(&buf[offsets[#nats_1]..])
93 ),* }
94 }
95
96 fn write<W: ::std::io::Write>(&self, writer: &mut W) -> ::std::io::Result<()> {
97 #( ::npy::Serializable::write(&self.#idents_c, writer)?; )*
98 Ok(())
99 }
100 }
101 }
102}