mev-proc-impl 0.1.1

mev procedural macros implementation
Documentation
use proc_easy::private::Spanned;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn;

pub fn derive(input: &syn::DeriveInput, mev: &TokenStream) -> syn::Result<TokenStream> {
    let name = &input.ident;
    let vis = &input.vis;

    if !input.generics.params.is_empty() {
        return Err(syn::Error::new_spanned(
            &input.generics,
            "generic arguments are not supported by `#[derive(DeviceRepr)]`",
        ));
    }

    let data = match &input.data {
        syn::Data::Struct(data) => data,
        _ => {
            return Err(syn::Error::new_spanned(
                input,
                "only structs are supported by `#[derive(DeviceRepr)]`",
            ))
        }
    };

    let name_repr = quote::format_ident!("__MevGenerated{}Pod", name);

    let field_types = data
        .fields
        .iter()
        .map(|field| &field.ty)
        .collect::<Vec<_>>();

    let field_pad_sizes = data
        .fields
        .iter()
        .enumerate()
        .map(|(idx, field)| {
            let end = data
                .fields
                .iter()
                .take(idx)
                .fold(quote! { 0 }, |acc, field| {
                    let ty = &field.ty;
                    quote_spanned! { ty.span() => #mev::for_macro::repr_append_field::<#ty>(#acc) }
                });

            let ty = &field.ty;
            quote::quote_spanned! {
                ty.span() => #mev::for_macro::repr_pad_for::<#ty>(#end)
            }
        })
        .collect::<Vec<_>>();

    let tail = data.fields.iter().fold(quote! { 0 }, |acc, field| {
        let ty = &field.ty;
        quote_spanned! { ty.span() => #mev::for_macro::repr_append_field::<#ty>(#acc) }
    });

    let total_align = data.fields.iter().fold(quote! { 0 }, |acc, field| {
        let ty = &field.ty;
        quote_spanned! { ty.span() => #acc | (#mev::for_macro::repr_align_of::<#ty>() - 1) }
    });

    let tail_pad = quote::quote!(#mev::for_macro::pad_align(#tail, (#total_align) + 1));

    match data.fields {
        syn::Fields::Named(_) => {
            let field_names = data
                .fields
                .iter()
                .map(|field| &field.ident)
                .collect::<Vec<_>>();

            let pad_names = data
                .fields
                .iter()
                .map(|field| {
                    quote::format_ident!(
                        "_mev_device_repr_pad_before_{}",
                        field.ident.as_ref().unwrap()
                    )
                })
                .collect::<Vec<_>>();

            let tokens = quote::quote! {
                #[allow(unused, non_camel_case_types)]
                #[repr(C)]
                #[doc(hidden)]
                #[derive(Clone, Copy, Debug)]
                #vis struct #name_repr {
                    #(
                        #[allow(non_snake_case)]
                        #pad_names: [u8; #field_pad_sizes],
                        #field_names: <#field_types as #mev::for_macro::DeviceRepr>::Repr,
                    )*
                    _mev_tail_pad: [u8; #tail_pad],
                }

                unsafe impl #mev::for_macro::Zeroable for #name_repr {}
                unsafe impl #mev::for_macro::Pod for #name_repr {}

                impl #mev::for_macro::DeviceRepr for #name {
                    type Repr = #name_repr;
                    type ArrayRepr = #name_repr;

                    #[inline(always)]
                    fn as_repr(&self) -> #name_repr {
                        #name_repr {
                            #(
                                #pad_names: [0xDAu8; #field_pad_sizes],
                                #field_names: #mev::for_macro::DeviceRepr::as_repr(&self.#field_names),
                            )*
                            _mev_tail_pad: [0xDAu8; #tail_pad],
                        }
                    }

                    #[inline(always)]
                    fn as_array_repr(&self) -> #name_repr {
                        self.as_repr()
                    }

                    const ALIGN: usize = 1 + (#total_align);
                }
            };

            Ok(tokens)
        }
        _ => todo!(),
    }
}