1extern crate proc_macro;
2
3use syn::{Data, DeriveInput, Error, Fields, parse_macro_input};
4use quote::quote;
5
6#[proc_macro_derive(Fields)]
7pub fn fields_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
8 let ast: syn::DeriveInput = parse_macro_input!(input as DeriveInput);
9 let ident = &ast.ident;
10 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
11 let data = match ast.data {
12 Data::Struct(ref data) => data,
13 _ => {
14 let e = Error::new_spanned(&ast, "trait `Fields` can only be implemented for structs");
15 return proc_macro::TokenStream::from(e.to_compile_error());
16 }
17 };
18 match data.fields {
19 Fields::Named(_) => {},
20 _ => {
21 let e = Error::new_spanned(&ast, "trait `Fields` can only be implemented for named fields");
22 return proc_macro::TokenStream::from(e.to_compile_error());
23 }
24 }
25
26 let offsets = data.fields.iter().map(|field| &field.ident);
27 let sizes = data.fields.iter().map(|field| &field.ty);
28 let aligns = data.fields.iter().map(|field| &field.ty);
29
30 let vis = data.fields.iter().map(|field| &field.vis);
31 let field = data.fields.iter().map(|field| &field.ident);
32 let ty = data.fields.iter().map(|field| &field.ty);
33 let index = 0..data.fields.iter().count();
34
35 let expanded = quote! {
36 unsafe impl #impl_generics ::dioptre::Fields for #ident #ty_generics #where_clause {
37 const OFFSETS: &'static [fn(*mut u8) -> usize] = &[
38 #(|object| unsafe {
39 let #ident { #offsets: ref field, .. } = *(object as *mut Self);
40 let offset = (field as *const _ as usize) - (object as *const _ as usize);
41 offset
42 },)*
43 ];
44
45 const SIZES: &'static [usize] = &[
46 #(::core::mem::size_of::<#sizes>(),)*
47 ];
48
49 const ALIGNS: &'static [usize] = &[
50 #(::core::mem::align_of::<#aligns>(),)*
51 ];
52 }
53
54 #[allow(non_upper_case_globals)]
55 impl #impl_generics #ident #ty_generics #where_clause {
56 #(#vis const #field: ::dioptre::Field<Self, #ty> = unsafe {
57 ::dioptre::Field::new(#index)
58 };)*
59 }
60 };
61
62 proc_macro::TokenStream::from(expanded)
63}