parasol_cpu_macros/
lib.rs1#![deny(missing_docs)]
2#![deny(rustdoc::broken_intra_doc_links)]
3extern crate proc_macro;
6use proc_macro::TokenStream;
7use proc_macro2::TokenStream as TokenStream2;
8use quote::quote;
9use syn::{Data, DeriveInput, Fields, parse_macro_input};
10
11#[proc_macro_derive(IntoBytes)]
12pub fn derive_into_bytes(item: TokenStream) -> TokenStream {
15 let input = parse_macro_input!(item as DeriveInput);
16
17 derive_into_bytes_impl(input).into()
18}
19
20fn derive_into_bytes_impl(item: DeriveInput) -> TokenStream2 {
21 let ident = item.ident;
22 let data = item.data;
23
24 let fields = match data {
25 Data::Struct(x) => x.fields,
26 _ => {
27 return quote! {
28 compile_error!("Only structs are supported for derive IntoBytes")
29 };
30 }
31 };
32
33 let field_idents = match &fields {
34 Fields::Unnamed(x) => x
35 .unnamed
36 .iter()
37 .enumerate()
38 .map(|(i, _)| quote! { #i })
39 .collect::<Vec<_>>(),
40 Fields::Named(x) => x
41 .named
42 .iter()
43 .map(|f| {
44 let ident = f.ident.clone().unwrap();
45
46 quote! { #ident }
47 })
48 .collect::<Vec<_>>(),
49 Fields::Unit => {
50 return quote! {
51 compile_error("Structs must have at least one member.")
52 };
53 }
54 };
55
56 let field_types = fields.iter().cloned().map(|x| x.ty).collect::<Vec<_>>();
57
58 let mut prev_field_size = vec![quote! { 0usize }];
59
60 for f in field_types.iter().take(field_types.len() - 1) {
61 prev_field_size.push(quote! {
62 <#f as tfhe_cpu::IntoBytes>::size()
63 })
64 }
65
66 let last_field_type = field_types.iter().last().unwrap();
67
68 quote! {
69 impl tfhe_cpu::IntoBytes for #ident {
70 #[inline(always)]
71 fn alignment() -> usize {
72 let mut alignment = 0usize;
73
74 #(alignment = alignment.max(<#field_types as tfhe_cpu::IntoBytes>::alignment());)*
75
76 alignment
77 }
78
79 #[inline(always)]
80 fn size() -> usize {
81 let mut cur_offset = 0;
82
83 #(
84 cur_offset += #prev_field_size;
85 cur_offset = cur_offset.next_multiple_of(<#field_types as tfhe_cpu::IntoBytes>::alignment());
86 )*
87
88 cur_offset += <#last_field_type as tfhe_cpu::IntoBytes>::size();
89
90 cur_offset
91 }
92
93 fn try_into_bytes(&self, data: &mut [u8]) -> tfhe_cpu::Result<()> {
94 if data.len() != Self::size() {
95 return Err(tfhe_cpu::Error::buffer_size_mismatch());
96 }
97
98 let mut cur_offset = 0;
99
100 #(
101 cur_offset += #prev_field_size;
102 cur_offset = cur_offset.next_multiple_of(<#field_types as tfhe_cpu::IntoBytes>::alignment());
103
104 let byte_slice = &mut data[cur_offset..cur_offset + <#field_types as tfhe_cpu::IntoBytes>::size()];
105 <#field_types as tfhe_cpu::IntoBytes>::try_into_bytes(&self. #field_idents, byte_slice)?;
106 )*
107
108 Ok(())
109 }
110
111 fn try_from_bytes(data: &[u8]) -> tfhe_cpu::Result<Self> {
112 if data.len() != Self::size() {
113 return Err(tfhe_cpu::Error::buffer_size_mismatch());
114 }
115
116 let mut cur_offset = 0;
117
118 #(
119 cur_offset += #prev_field_size;
120 cur_offset = cur_offset.next_multiple_of(<#field_types as tfhe_cpu::IntoBytes>::alignment());
121
122 let byte_slice = &data[cur_offset..cur_offset + <#field_types as tfhe_cpu::IntoBytes>::size()];
123 let #field_idents = <#field_types as tfhe_cpu::IntoBytes>::try_from_bytes( byte_slice)?;
124 )*
125
126
127 Ok(Self {
128 #(#field_idents,)*
129 })
130 }
131 }
132 }
133}