1use proc_macro2::TokenStream as TokenStream2;
6use quote::quote;
7
8use crate::utils::{self, FieldInfo};
9use syn::spanned::Spanned;
10use syn::{Data, DeriveInput, Error};
11
12pub fn derive_impl(input: &DeriveInput) -> TokenStream2 {
13 if !utils::ReprInfo::compute(&input.attrs).cpacked_or_transparent() {
14 return Error::new(
15 input.span(),
16 "derive(ULE) must be applied to a #[repr(C, packed)] or #[repr(transparent)] type",
17 )
18 .to_compile_error();
19 }
20 if input.generics.type_params().next().is_some()
21 || input.generics.lifetimes().next().is_some()
22 || input.generics.const_params().next().is_some()
23 {
24 return Error::new(
25 input.generics.span(),
26 "derive(ULE) must be applied to a struct without any generics",
27 )
28 .to_compile_error();
29 }
30 let struc = if let Data::Struct(ref s) = input.data {
31 if s.fields.iter().next().is_none() {
32 return Error::new(
33 input.span(),
34 "derive(ULE) must be applied to a non-empty struct",
35 )
36 .to_compile_error();
37 }
38 s
39 } else {
40 return Error::new(input.span(), "derive(ULE) must be applied to a struct")
41 .to_compile_error();
42 };
43
44 let fields = FieldInfo::make_list(struc.fields.iter());
45 let (validators, remaining_offset) = generate_ule_validators(&fields);
46
47 let name = &input.ident;
48
49 {
let mut _s = ::quote::__private::TokenStream::new();
::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, "ULE");
::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, "const");
::quote::__private::push_ident(&mut _s, "SIZE");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "usize");
::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, "size_of");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_gt(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_semi(&mut _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, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "clippy");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "modulo_one");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "if");
::quote::__private::push_ident(&mut _s, "bytes");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "len");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_rem(&mut _s);
::quote::__private::push_ident(&mut _s, "SIZE");
::quote::__private::push_ne(&mut _s);
::quote::__private::parse(&mut _s, "0");
::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, "length");
::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,
{
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, "len");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
});
_s
});
::quote::__private::push_semi(&mut _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, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "clippy");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "indexing_slicing");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "for");
::quote::__private::push_ident(&mut _s, "chunk");
::quote::__private::push_ident(&mut _s, "in");
::quote::__private::push_ident(&mut _s, "bytes");
::quote::__private::push_dot(&mut _s);
::quote::__private::push_ident(&mut _s, "chunks_exact");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "SIZE");
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&validators, &mut _s);
::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::__private::push_ident(&mut _s, "SIZE");
_s
});
::quote::__private::push_semi(&mut _s);
_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
});
_s
});
_s
}quote! {
59 unsafe impl zerovec::ule::ULE for #name {
60 #[inline]
61 fn validate_bytes(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
62 const SIZE: usize = ::core::mem::size_of::<#name>();
63 #[allow(clippy::modulo_one)]
64 if bytes.len() % SIZE != 0 {
65 return Err(zerovec::ule::UleError::length::<Self>(bytes.len()));
66 }
67 #[allow(clippy::indexing_slicing)] for chunk in bytes.chunks_exact(SIZE) {
70 #validators
71 debug_assert_eq!(#remaining_offset, SIZE);
72 }
73 Ok(())
74 }
75 }
76 }
77}
78
79pub(crate) fn generate_ule_validators(
83 fields: &[FieldInfo],
84 ) -> (TokenStream2, syn::Ident) {
86 utils::generate_per_field_offsets(fields, false, |field, prev_offset_ident, size_ident| {
87 let ty = &field.field.ty;
88 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "if");
::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, "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(&prev_offset_ident, &mut _s);
::quote::__private::push_dot2(&mut _s);
::quote::ToTokens::to_tokens(&prev_offset_ident, &mut _s);
::quote::__private::push_add(&mut _s);
::quote::ToTokens::to_tokens(&size_ident, &mut _s);
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &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, "ULE");
::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, "bytes");
_s
});
::quote::__private::push_question(&mut _s);
::quote::__private::push_semi(&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
});
_s
}quote! {
89 if let Some(bytes) = bytes.get(#prev_offset_ident .. #prev_offset_ident + #size_ident) {
90 <#ty as zerovec::ule::ULE>::validate_bytes(bytes)?;
91 } else {
92 return Err(zerovec::ule::UleError::parse::<Self>());
93 }
94 }
95 })
96}
97
98pub(crate) fn make_ule_fields(fields: &[FieldInfo]) -> Vec<TokenStream2> {
100 fields
101 .iter()
102 .map(|f| {
103 let ty = &f.field.ty;
104 let ty = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&ty, &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, "AsULE");
::quote::__private::push_gt(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ULE");
_s
}quote!(<#ty as zerovec::ule::AsULE>::ULE);
105 let setter = f.setter();
106 let vis = &f.field.vis;
107 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&vis, &mut _s);
::quote::ToTokens::to_tokens(&setter, &mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
_s
}quote!(#vis #setter #ty)
108 })
109 .collect::<Vec<_>>()
110}