1use crate::utils::{self, FieldInfo};
6use proc_macro2::Span;
7use proc_macro2::TokenStream as TokenStream2;
8use quote::quote;
9use syn::spanned::Spanned;
10use syn::{Data, DeriveInput, Error, Ident};
11
12pub fn derive_impl(
15 input: &DeriveInput,
16 custom_varule_validator: Option<TokenStream2>,
17) -> TokenStream2 {
18 if !utils::ReprInfo::compute(&input.attrs).cpacked_or_transparent() {
19 return Error::new(
20 input.span(),
21 "derive(VarULE) must be applied to a #[repr(C, packed)] or #[repr(transparent)] type",
22 )
23 .to_compile_error();
24 }
25 if input.generics.type_params().next().is_some()
26 || input.generics.lifetimes().next().is_some()
27 || input.generics.const_params().next().is_some()
28 {
29 return Error::new(
30 input.generics.span(),
31 "derive(VarULE) must be applied to a struct without any generics",
32 )
33 .to_compile_error();
34 }
35 let struc = if let Data::Struct(ref s) = input.data {
36 if s.fields.iter().next().is_none() {
37 return Error::new(
38 input.span(),
39 "derive(VarULE) must be applied to a non-empty struct",
40 )
41 .to_compile_error();
42 }
43 s
44 } else {
45 return Error::new(input.span(), "derive(VarULE) must be applied to a struct")
46 .to_compile_error();
47 };
48
49 let n_fields = struc.fields.len();
50
51 let ule_fields = FieldInfo::make_list(struc.fields.iter().take(n_fields - 1));
52
53 let sizes = ule_fields.iter().map(|f| {
54 let ty = &f.field.ty;
55 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mem");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "size_of");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote!(::core::mem::size_of::<#ty>())
56 });
57 let (validators, remaining_offset) = if n_fields > 1 {
58 crate::ule::generate_ule_validators(&ule_fields)
60 } else {
61 (
63 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "ZERO");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "usize");
::quote::__private::push_eq(&mut _s);
::quote::__private::parse(&mut _s, "0");
::quote::__private::push_semi(&mut _s);
_s
}quote!(
64 const ZERO: usize = 0;
65 ),
66 Ident::new("ZERO", Span::call_site()),
67 )
68 };
69
70 let unsized_field = &struc
71 .fields
72 .iter()
73 .next_back()
74 .expect("Already verified that struct is not empty")
75 .ty;
76
77 let name = &input.ident;
78 let ule_size = Ident::new(
79 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__IMPL_VarULE_FOR_{0}_ULE_SIZE",
name))
})format!("__IMPL_VarULE_FOR_{name}_ULE_SIZE"),
80 Span::call_site(),
81 );
82
83 let last_field_validator = if let Some(custom_varule_validator) = custom_varule_validator {
84 custom_varule_validator
85 } else {
86 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&unsized_field, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_ident(&mut _s, "zerovec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ule");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "VarULE");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "validate_bytes");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "last_field_bytes");
_s
});
::quote::__private::push_question(&mut _s);
::quote::__private::push_semi(&mut _s);
_s
}quote!(<#unsized_field as zerovec::ule::VarULE>::validate_bytes(last_field_bytes)?;)
87 };
88
89 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "const");
::quote::ToTokens::to_tokens(&ule_size, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "usize");
::quote::__private::push_eq(&mut _s);
::quote::__private::parse(&mut _s, "0");
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut sizes, i) = sizes.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let sizes =
match sizes.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::__private::push_add(&mut _s);
::quote::ToTokens::to_tokens(&sizes, &mut _s);
}
}
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_ident(&mut _s, "impl");
::quote::__private::push_ident(&mut _s, "zerovec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ule");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "VarULE");
::quote::__private::push_ident(&mut _s, "for");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "inline");
_s
});
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "validate_bytes");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "bytes");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "u8");
_s
});
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_ident(&mut _s, "Result");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "zerovec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ule");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "UleError");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "debug_assert_eq");
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&remaining_offset, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&ule_size, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "Some");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "last_field_bytes");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "bytes");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "get");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&remaining_offset, &mut _s);
::quote::__private::push_dot2(&mut _s);
_s
});
::quote::__private::push_ident(&mut _s, "else");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "return");
::quote::__private::push_ident(&mut _s, "Err");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "zerovec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ule");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "UleError");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "parse");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
::quote::__private::push_semi(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::ToTokens::to_tokens(&validators, &mut _s);
::quote::ToTokens::to_tokens(&last_field_validator,
&mut _s);
::quote::__private::push_ident(&mut _s, "Ok");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
});
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "inline");
_s
});
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "from_bytes_unchecked");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "bytes");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "u8");
_s
});
_s
});
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "unsized_bytes");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_ident(&mut _s, "bytes");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "get_unchecked");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ule_size, &mut _s);
::quote::__private::push_dot2(&mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s, "unsized_ref");
::quote::__private::push_eq(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&unsized_field, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_ident(&mut _s, "zerovec");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ule");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "VarULE");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"from_bytes_unchecked");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsized_bytes");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "_ptr");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "metadata");
_s
});
::quote::__private::push_colon(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "usize");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "usize");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "mem");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "transmute");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "unsized_ref");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "let");
::quote::__private::push_ident(&mut _s,
"entire_struct_as_slice");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "u8");
_s
});
::quote::__private::push_eq(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "core");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "slice");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "from_raw_parts");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "bytes");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "as_ptr");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "metadata");
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_star(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s,
"entire_struct_as_slice");
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_star(&mut _s);
::quote::__private::push_ident(&mut _s, "const");
::quote::__private::push_ident(&mut _s, "Self");
_s
});
_s
});
_s
});
_s
}quote! {
100 const #ule_size: usize = 0 #(+ #sizes)*;
102 unsafe impl zerovec::ule::VarULE for #name {
103 #[inline]
104 fn validate_bytes(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
105 debug_assert_eq!(#remaining_offset, #ule_size);
106
107 let Some(last_field_bytes) = bytes.get(#remaining_offset..) else {
108 return Err(zerovec::ule::UleError::parse::<Self>());
109 };
110 #validators
111 #last_field_validator
112 Ok(())
113 }
114 #[inline]
115 unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
116 let unsized_bytes = bytes.get_unchecked(#ule_size..);
120 let unsized_ref = <#unsized_field as zerovec::ule::VarULE>::from_bytes_unchecked(unsized_bytes);
121 let (_ptr, metadata): (usize, usize) = ::core::mem::transmute(unsized_ref);
124 let entire_struct_as_slice: *const [u8] = ::core::slice::from_raw_parts(bytes.as_ptr(), metadata);
125 &*(entire_struct_as_slice as *const Self)
126 }
127 }
128 }
129}