Skip to main content

dioptre_derive/
lib.rs

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}