alignment_exporter_derive/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput};
4
5#[proc_macro_attribute]
7pub fn export_alignment(_attr: TokenStream, item: TokenStream) -> TokenStream {
8 let input = parse_macro_input!(item as DeriveInput);
9 let struct_name = &input.ident;
10 let data = match &input.data {
11 Data::Struct(data) => data,
12 _ => {
13 return TokenStream::from(quote! {
14 compile_error!("export_alignment can only be used on structs");
15 });
16 }
17 };
18 let mut code = Vec::new();
19 if let syn::Fields::Named(ref fields) = data.fields {
20 for field in &fields.named {
21 let ty = &field.ty;
22 code.push(quote! {{
23 let size = std::mem::size_of::<#ty>();
24 let alignment = std::mem::align_of::<#ty>();
25 result.push(::alignment_exporter::Alignment {
26 size,
27 offset,
28 ty_name: stringify!(#ty)
29 });
30 if alignment > max_alignment {
31 max_alignment = alignment;
32 }
33 if offset % alignment != 0 {
34 let padding = alignment - (offset % alignment);
35 offset += padding;
36 }
37 let field_offset = offset;
38 offset += size;
39 }});
40 }
41 }
42 let output = quote! {
43 #[repr(C)]
44 #input
45
46 impl ::alignment_exporter::AlignmentExporter for #struct_name {
47 fn get_alignment() -> &'static [::alignment_exporter::Alignment] {
48 static RESULT: ::std::sync::LazyLock<::std::vec::Vec<::alignment_exporter::Alignment>> = ::std::sync::LazyLock::new(|| {
49 let mut result = ::std::vec::Vec::new();
50 let mut offset = 0;
51 let mut max_alignment = 0;
52 #(#code)*
53 result
54 });
55 RESULT.as_slice()
56 }
57 }
58 };
59 output.into()
60}