npy_derive/
lib.rs

1#![recursion_limit = "128"]
2
3/*!
4Derive `trait Serializable` for a structure.
5
6Using this crate, it is enough to `#[derive(Serializable)]` on a struct to be able to serialize and
7deserialize it. All the fields must implement [`Serializable`](../npy/trait.Serializable.html).
8
9*/
10
11extern 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/// Macros 1.1-based custom derive function
21#[proc_macro_derive(Serializable)]
22pub fn npy_data(input: TokenStream) -> TokenStream {
23    // Construct a string representation of the type definition
24    // let s = input.to_string();
25
26    // Parse the string representation
27    let ast = syn::parse(input).unwrap();
28
29    // Build the impl
30    let expanded = impl_npy_data(&ast);
31
32    // Return the generated impl
33    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    // Helper is provided for handling complex generic types correctly and effortlessly
43    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}