use {
crate::common::{get_crate_name, SchemaArgs, StructRepr},
darling::{ast::Data, Error, Result},
proc_macro2::TokenStream,
quote::quote,
};
pub(crate) fn assert_zero_copy(args: &SchemaArgs, repr: &StructRepr) -> Result<TokenStream> {
if !args.assert_zero_copy {
return Ok(quote! {});
}
let crate_name = get_crate_name(args);
let ident = &args.ident;
let zero_copy_field_asserts = match &args.data {
Data::Struct(fields) => fields.iter().map(|field| {
let target = field.target_resolved();
quote! { assert_field_zerocopy_impl::<#target>() }
}),
_ => return Err(Error::custom("`ZeroCopy` can only be derived for structs")),
};
if !repr.is_zero_copy_eligible() {
return Err(Error::custom(
"The struct representation is not eligible for zero-copy. Consider using \
#[repr(transparent)] or #[repr(C)] on the struct.",
));
}
Ok(quote! {
const _: () = {
const _assert_schema_read_impl: fn() = || {
fn assert_schema_read_impl<'de, T: #crate_name::SchemaRead<'de>>() {}
assert_schema_read_impl::<#ident>()
};
const _assert_field_zerocopy_impl: fn() = || {
fn assert_field_zerocopy_impl<T: #crate_name::ZeroCopy>() {}
#(#zero_copy_field_asserts);*
};
const _assert_no_padding: () = {
if let #crate_name::TypeMeta::Static { size, .. } = <#ident as #crate_name::SchemaRead<'_>>::TYPE_META {
if size != core::mem::size_of::<#ident>() {
panic!("wincode(assert_zero_copy) was applied to a type with padding");
}
} else {
panic!("wincode(assert_zero_copy) was applied to a type with `TypeMeta::Dynamic`");
}
};
};
})
}