Added custom crate path with tests (#209)

Co-authored-by: Andri <80914617+Shuray04@users.noreply.github.com>
This commit is contained in:
Andri 2023-10-20 07:02:54 +02:00 committed by GitHub
parent fd27a5b018
commit c705218630
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 67 deletions

View File

@ -9,8 +9,8 @@ use quote::quote;
use syn::{parse_macro_input, DeriveInput, Result}; use syn::{parse_macro_input, DeriveInput, Result};
use crate::traits::{ use crate::traits::{
AnyBitPattern, CheckedBitPattern, Contiguous, Derivable, NoUninit, Pod, bytemuck_crate_name, AnyBitPattern, CheckedBitPattern, Contiguous, Derivable,
TransparentWrapper, Zeroable, NoUninit, Pod, TransparentWrapper, Zeroable,
}; };
/// Derive the `Pod` trait for a struct /// Derive the `Pod` trait for a struct
@ -87,7 +87,7 @@ use crate::traits::{
/// ///
/// let _: u32 = bytemuck::cast(Generic { a: 4u32, b: PhantomData::<NotPod> }); /// let _: u32 = bytemuck::cast(Generic { a: 4u32, b: PhantomData::<NotPod> });
/// ``` /// ```
#[proc_macro_derive(Pod)] #[proc_macro_derive(Pod, attributes(bytemuck))]
pub fn derive_pod(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn derive_pod(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let expanded = let expanded =
derive_marker_trait::<Pod>(parse_macro_input!(input as DeriveInput)); derive_marker_trait::<Pod>(parse_macro_input!(input as DeriveInput));
@ -103,7 +103,7 @@ pub fn derive_pod(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
/// The following constraints need to be satisfied for the macro to succeed /// The following constraints need to be satisfied for the macro to succeed
/// ///
/// - All fields in the struct must to implement `AnyBitPattern` /// - All fields in the struct must to implement `AnyBitPattern`
#[proc_macro_derive(AnyBitPattern)] #[proc_macro_derive(AnyBitPattern, attributes(bytemuck))]
pub fn derive_anybitpattern( pub fn derive_anybitpattern(
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {
@ -192,7 +192,7 @@ pub fn derive_anybitpattern(
/// # } /// # }
/// ZeroableWhenTIsZeroable::<String>::zeroed(); /// ZeroableWhenTIsZeroable::<String>::zeroed();
/// ``` /// ```
#[proc_macro_derive(Zeroable, attributes(zeroable))] #[proc_macro_derive(Zeroable, attributes(bytemuck, zeroable))]
pub fn derive_zeroable( pub fn derive_zeroable(
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {
@ -319,7 +319,7 @@ pub fn derive_maybe_pod(
/// another_extra: NonTransparentSafeZST, // not `Zeroable` /// another_extra: NonTransparentSafeZST, // not `Zeroable`
/// } /// }
/// ``` /// ```
#[proc_macro_derive(TransparentWrapper, attributes(transparent))] #[proc_macro_derive(TransparentWrapper, attributes(bytemuck, transparent))]
pub fn derive_transparent( pub fn derive_transparent(
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {
@ -394,6 +394,7 @@ pub fn derive_byte_eq(
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput); let input = parse_macro_input!(input as DeriveInput);
let crate_name = bytemuck_crate_name(&input);
let ident = input.ident; let ident = input.ident;
proc_macro::TokenStream::from(quote! { proc_macro::TokenStream::from(quote! {
@ -401,7 +402,7 @@ pub fn derive_byte_eq(
#[inline] #[inline]
#[must_use] #[must_use]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
::bytemuck::bytes_of(self) == ::bytemuck::bytes_of(other) #crate_name::bytes_of(self) == #crate_name::bytes_of(other)
} }
} }
impl ::core::cmp::Eq for #ident { } impl ::core::cmp::Eq for #ident { }
@ -434,18 +435,19 @@ pub fn derive_byte_hash(
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput); let input = parse_macro_input!(input as DeriveInput);
let crate_name = bytemuck_crate_name(&input);
let ident = input.ident; let ident = input.ident;
proc_macro::TokenStream::from(quote! { proc_macro::TokenStream::from(quote! {
impl ::core::hash::Hash for #ident { impl ::core::hash::Hash for #ident {
#[inline] #[inline]
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) { fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
::core::hash::Hash::hash_slice(::bytemuck::bytes_of(self), state) ::core::hash::Hash::hash_slice(#crate_name::bytes_of(self), state)
} }
#[inline] #[inline]
fn hash_slice<H: ::core::hash::Hasher>(data: &[Self], state: &mut H) { fn hash_slice<H: ::core::hash::Hasher>(data: &[Self], state: &mut H) {
::core::hash::Hash::hash_slice(::bytemuck::cast_slice::<_, u8>(data), state) ::core::hash::Hash::hash_slice(#crate_name::cast_slice::<_, u8>(data), state)
} }
} }
}) })
@ -518,7 +520,8 @@ fn find_and_parse_helper_attributes<P: syn::parse::Parser + Copy>(
fn derive_marker_trait_inner<Trait: Derivable>( fn derive_marker_trait_inner<Trait: Derivable>(
mut input: DeriveInput, mut input: DeriveInput,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let trait_ = Trait::ident(&input)?; let crate_name = bytemuck_crate_name(&input);
let trait_ = Trait::ident(&input, &crate_name)?;
// If this trait allows explicit bounds, and any explicit bounds were given, // If this trait allows explicit bounds, and any explicit bounds were given,
// then use those explicit bounds. Else, apply the default bounds (bound // then use those explicit bounds. Else, apply the default bounds (bound
// each generic type on this trait). // each generic type on this trait).
@ -585,10 +588,12 @@ fn derive_marker_trait_inner<Trait: Derivable>(
input.generics.split_for_impl(); input.generics.split_for_impl();
Trait::check_attributes(&input.data, &input.attrs)?; Trait::check_attributes(&input.data, &input.attrs)?;
let asserts = Trait::asserts(&input)?; let asserts = Trait::asserts(&input, &crate_name)?;
let (trait_impl_extras, trait_impl) = Trait::trait_impl(&input)?; let (trait_impl_extras, trait_impl) = Trait::trait_impl(&input, &crate_name)?;
let implies_trait = if let Some(implies_trait) = Trait::implies_trait() { let implies_trait = if let Some(implies_trait) =
Trait::implies_trait(&crate_name)
{
quote!(unsafe impl #impl_generics #implies_trait for #name #ty_generics #where_clause {}) quote!(unsafe impl #impl_generics #implies_trait for #name #ty_generics #where_clause {})
} else { } else {
quote!() quote!()

View File

@ -21,17 +21,17 @@ macro_rules! bail {
} }
pub trait Derivable { pub trait Derivable {
fn ident(input: &DeriveInput) -> Result<syn::Path>; fn ident(input: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path>;
fn implies_trait() -> Option<TokenStream> { fn implies_trait(_crate_name: &TokenStream) -> Option<TokenStream> {
None None
} }
fn asserts(_input: &DeriveInput) -> Result<TokenStream> { fn asserts(_input: &DeriveInput, _crate_name: &TokenStream) -> Result<TokenStream> {
Ok(quote!()) Ok(quote!())
} }
fn check_attributes(_ty: &Data, _attributes: &[Attribute]) -> Result<()> { fn check_attributes(_ty: &Data, _attributes: &[Attribute]) -> Result<()> {
Ok(()) Ok(())
} }
fn trait_impl(_input: &DeriveInput) -> Result<(TokenStream, TokenStream)> { fn trait_impl(_input: &DeriveInput, _crate_name: &TokenStream) -> Result<(TokenStream, TokenStream)> {
Ok((quote!(), quote!())) Ok((quote!(), quote!()))
} }
fn requires_where_clause() -> bool { fn requires_where_clause() -> bool {
@ -45,11 +45,11 @@ pub trait Derivable {
pub struct Pod; pub struct Pod;
impl Derivable for Pod { impl Derivable for Pod {
fn ident(_: &DeriveInput) -> Result<syn::Path> { fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
Ok(syn::parse_quote!(::bytemuck::Pod)) Ok(syn::parse_quote!(#crate_name::Pod))
} }
fn asserts(input: &DeriveInput) -> Result<TokenStream> { fn asserts(input: &DeriveInput, crate_name: &TokenStream) -> Result<TokenStream> {
let repr = get_repr(&input.attrs)?; let repr = get_repr(&input.attrs)?;
let completly_packed = let completly_packed =
@ -71,7 +71,7 @@ impl Derivable for Pod {
None None
}; };
let assert_fields_are_pod = let assert_fields_are_pod =
generate_fields_are_trait(input, Self::ident(input)?)?; generate_fields_are_trait(input, Self::ident(input, crate_name)?)?;
Ok(quote!( Ok(quote!(
#assert_no_padding #assert_no_padding
@ -98,18 +98,18 @@ impl Derivable for Pod {
pub struct AnyBitPattern; pub struct AnyBitPattern;
impl Derivable for AnyBitPattern { impl Derivable for AnyBitPattern {
fn ident(_: &DeriveInput) -> Result<syn::Path> { fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
Ok(syn::parse_quote!(::bytemuck::AnyBitPattern)) Ok(syn::parse_quote!(#crate_name::AnyBitPattern))
} }
fn implies_trait() -> Option<TokenStream> { fn implies_trait(crate_name: &TokenStream) -> Option<TokenStream> {
Some(quote!(::bytemuck::Zeroable)) Some(quote!(#crate_name::Zeroable))
} }
fn asserts(input: &DeriveInput) -> Result<TokenStream> { fn asserts(input: &DeriveInput, crate_name: &TokenStream) -> Result<TokenStream> {
match &input.data { match &input.data {
Data::Union(_) => Ok(quote!()), // unions are always `AnyBitPattern` Data::Union(_) => Ok(quote!()), // unions are always `AnyBitPattern`
Data::Struct(_) => generate_fields_are_trait(input, Self::ident(input)?), Data::Struct(_) => generate_fields_are_trait(input, Self::ident(input, crate_name)?),
Data::Enum(_) => { Data::Enum(_) => {
bail!("Deriving AnyBitPattern is not supported for enums") bail!("Deriving AnyBitPattern is not supported for enums")
} }
@ -120,14 +120,14 @@ impl Derivable for AnyBitPattern {
pub struct Zeroable; pub struct Zeroable;
impl Derivable for Zeroable { impl Derivable for Zeroable {
fn ident(_: &DeriveInput) -> Result<syn::Path> { fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
Ok(syn::parse_quote!(::bytemuck::Zeroable)) Ok(syn::parse_quote!(#crate_name::Zeroable))
} }
fn asserts(input: &DeriveInput) -> Result<TokenStream> { fn asserts(input: &DeriveInput, crate_name: &TokenStream) -> Result<TokenStream> {
match &input.data { match &input.data {
Data::Union(_) => Ok(quote!()), // unions are always `Zeroable` Data::Union(_) => Ok(quote!()), // unions are always `Zeroable`
Data::Struct(_) => generate_fields_are_trait(input, Self::ident(input)?), Data::Struct(_) => generate_fields_are_trait(input, Self::ident(input, crate_name)?),
Data::Enum(_) => bail!("Deriving Zeroable is not supported for enums"), Data::Enum(_) => bail!("Deriving Zeroable is not supported for enums"),
} }
} }
@ -140,8 +140,8 @@ impl Derivable for Zeroable {
pub struct NoUninit; pub struct NoUninit;
impl Derivable for NoUninit { impl Derivable for NoUninit {
fn ident(_: &DeriveInput) -> Result<syn::Path> { fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
Ok(syn::parse_quote!(::bytemuck::NoUninit)) Ok(syn::parse_quote!(#crate_name::NoUninit))
} }
fn check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()> { fn check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()> {
@ -160,7 +160,7 @@ impl Derivable for NoUninit {
} }
} }
fn asserts(input: &DeriveInput) -> Result<TokenStream> { fn asserts(input: &DeriveInput, crate_name: &TokenStream) -> Result<TokenStream> {
if !input.generics.params.is_empty() { if !input.generics.params.is_empty() {
bail!("NoUninit cannot be derived for structs containing generic parameters because the padding requirements can't be verified for generic structs"); bail!("NoUninit cannot be derived for structs containing generic parameters because the padding requirements can't be verified for generic structs");
} }
@ -169,7 +169,7 @@ impl Derivable for NoUninit {
Data::Struct(DataStruct { .. }) => { Data::Struct(DataStruct { .. }) => {
let assert_no_padding = generate_assert_no_padding(&input)?; let assert_no_padding = generate_assert_no_padding(&input)?;
let assert_fields_are_no_padding = let assert_fields_are_no_padding =
generate_fields_are_trait(&input, Self::ident(input)?)?; generate_fields_are_trait(&input, Self::ident(input, crate_name)?)?;
Ok(quote!( Ok(quote!(
#assert_no_padding #assert_no_padding
@ -187,7 +187,7 @@ impl Derivable for NoUninit {
} }
} }
fn trait_impl(_input: &DeriveInput) -> Result<(TokenStream, TokenStream)> { fn trait_impl(_input: &DeriveInput, _crate_name: &TokenStream) -> Result<(TokenStream, TokenStream)> {
Ok((quote!(), quote!())) Ok((quote!(), quote!()))
} }
} }
@ -195,8 +195,8 @@ impl Derivable for NoUninit {
pub struct CheckedBitPattern; pub struct CheckedBitPattern;
impl Derivable for CheckedBitPattern { impl Derivable for CheckedBitPattern {
fn ident(_: &DeriveInput) -> Result<syn::Path> { fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
Ok(syn::parse_quote!(::bytemuck::CheckedBitPattern)) Ok(syn::parse_quote!(#crate_name::CheckedBitPattern))
} }
fn check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()> { fn check_attributes(ty: &Data, attributes: &[Attribute]) -> Result<()> {
@ -223,7 +223,7 @@ impl Derivable for CheckedBitPattern {
} }
} }
fn asserts(input: &DeriveInput) -> Result<TokenStream> { fn asserts(input: &DeriveInput, crate_name: &TokenStream) -> Result<TokenStream> {
if !input.generics.params.is_empty() { if !input.generics.params.is_empty() {
bail!("CheckedBitPattern cannot be derived for structs containing generic parameters"); bail!("CheckedBitPattern cannot be derived for structs containing generic parameters");
} }
@ -231,7 +231,7 @@ impl Derivable for CheckedBitPattern {
match &input.data { match &input.data {
Data::Struct(DataStruct { .. }) => { Data::Struct(DataStruct { .. }) => {
let assert_fields_are_maybe_pod = let assert_fields_are_maybe_pod =
generate_fields_are_trait(&input, Self::ident(input)?)?; generate_fields_are_trait(&input, Self::ident(input, crate_name)?)?;
Ok(assert_fields_are_maybe_pod) Ok(assert_fields_are_maybe_pod)
} }
@ -240,13 +240,13 @@ impl Derivable for CheckedBitPattern {
} }
} }
fn trait_impl(input: &DeriveInput) -> Result<(TokenStream, TokenStream)> { fn trait_impl(input: &DeriveInput, crate_name: &TokenStream) -> Result<(TokenStream, TokenStream)> {
match &input.data { match &input.data {
Data::Struct(DataStruct { fields, .. }) => { Data::Struct(DataStruct { fields, .. }) => {
generate_checked_bit_pattern_struct(&input.ident, fields, &input.attrs) generate_checked_bit_pattern_struct(&input.ident, fields, &input.attrs, crate_name)
} }
Data::Enum(DataEnum { variants, .. }) => { Data::Enum(DataEnum { variants, .. }) => {
generate_checked_bit_pattern_enum(input, variants) generate_checked_bit_pattern_enum(input, variants, crate_name)
} }
Data::Union(_) => bail!("Internal error in CheckedBitPattern derive"), /* shouldn't be possible since we already error in attribute check for this case */ Data::Union(_) => bail!("Internal error in CheckedBitPattern derive"), /* shouldn't be possible since we already error in attribute check for this case */
} }
@ -274,7 +274,7 @@ impl TransparentWrapper {
} }
impl Derivable for TransparentWrapper { impl Derivable for TransparentWrapper {
fn ident(input: &DeriveInput) -> Result<syn::Path> { fn ident(input: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
let fields = get_struct_fields(input)?; let fields = get_struct_fields(input)?;
let ty = match Self::get_wrapper_type(&input.attrs, &fields) { let ty = match Self::get_wrapper_type(&input.attrs, &fields) {
@ -287,10 +287,10 @@ impl Derivable for TransparentWrapper {
), ),
}; };
Ok(syn::parse_quote!(::bytemuck::TransparentWrapper<#ty>)) Ok(syn::parse_quote!(#crate_name::TransparentWrapper<#ty>))
} }
fn asserts(input: &DeriveInput) -> Result<TokenStream> { fn asserts(input: &DeriveInput, crate_name: &TokenStream) -> Result<TokenStream> {
let (impl_generics, _ty_generics, where_clause) = let (impl_generics, _ty_generics, where_clause) =
input.generics.split_for_impl(); input.generics.split_for_impl();
let fields = get_struct_fields(input)?; let fields = get_struct_fields(input)?;
@ -318,7 +318,7 @@ impl Derivable for TransparentWrapper {
const _: () = { const _: () = {
#[repr(transparent)] #[repr(transparent)]
struct AssertWrappedIsWrapped #impl_generics((u8, ::core::marker::PhantomData<#wrapped_field_ty>), #(#nonwrapped_field_tys),*) #where_clause; struct AssertWrappedIsWrapped #impl_generics((u8, ::core::marker::PhantomData<#wrapped_field_ty>), #(#nonwrapped_field_tys),*) #where_clause;
fn assert_zeroable<Z: ::bytemuck::Zeroable>() {} fn assert_zeroable<Z: #crate_name::Zeroable>() {}
fn check #impl_generics () #where_clause { fn check #impl_generics () #where_clause {
#( #(
assert_zeroable::<#nonwrapped_field_tys>(); assert_zeroable::<#nonwrapped_field_tys>();
@ -352,11 +352,11 @@ impl Derivable for TransparentWrapper {
pub struct Contiguous; pub struct Contiguous;
impl Derivable for Contiguous { impl Derivable for Contiguous {
fn ident(_: &DeriveInput) -> Result<syn::Path> { fn ident(_: &DeriveInput, crate_name: &TokenStream) -> Result<syn::Path> {
Ok(syn::parse_quote!(::bytemuck::Contiguous)) Ok(syn::parse_quote!(#crate_name::Contiguous))
} }
fn trait_impl(input: &DeriveInput) -> Result<(TokenStream, TokenStream)> { fn trait_impl(input: &DeriveInput, _crate_name: &TokenStream) -> Result<(TokenStream, TokenStream)> {
let repr = get_repr(&input.attrs)?; let repr = get_repr(&input.attrs)?;
let integer_ty = if let Some(integer_ty) = repr.repr.as_integer() { let integer_ty = if let Some(integer_ty) = repr.repr.as_integer() {
@ -460,7 +460,7 @@ fn get_field_types<'a>(
} }
fn generate_checked_bit_pattern_struct( fn generate_checked_bit_pattern_struct(
input_ident: &Ident, fields: &Fields, attrs: &[Attribute], input_ident: &Ident, fields: &Fields, attrs: &[Attribute], crate_name: &TokenStream
) -> Result<(TokenStream, TokenStream)> { ) -> Result<(TokenStream, TokenStream)> {
let bits_ty = Ident::new(&format!("{}Bits", input_ident), input_ident.span()); let bits_ty = Ident::new(&format!("{}Bits", input_ident), input_ident.span());
@ -486,10 +486,10 @@ fn generate_checked_bit_pattern_struct(
Ok(( Ok((
quote! { quote! {
#repr #repr
#[derive(Clone, Copy, ::bytemuck::AnyBitPattern)] #[derive(Clone, Copy, #crate_name::AnyBitPattern)]
#derive_dbg #derive_dbg
pub struct #bits_ty { pub struct #bits_ty {
#(#field_name: <#field_ty as ::bytemuck::CheckedBitPattern>::Bits,)* #(#field_name: <#field_ty as #crate_name::CheckedBitPattern>::Bits,)*
} }
}, },
quote! { quote! {
@ -498,17 +498,17 @@ fn generate_checked_bit_pattern_struct(
#[inline] #[inline]
#[allow(clippy::double_comparisons)] #[allow(clippy::double_comparisons)]
fn is_valid_bit_pattern(bits: &#bits_ty) -> bool { fn is_valid_bit_pattern(bits: &#bits_ty) -> bool {
#(<#field_ty as ::bytemuck::CheckedBitPattern>::is_valid_bit_pattern(&{ bits.#field_name }) && )* true #(<#field_ty as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(&{ bits.#field_name }) && )* true
} }
}, },
)) ))
} }
fn generate_checked_bit_pattern_enum( fn generate_checked_bit_pattern_enum(
input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>, input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>, crate_name: &TokenStream
) -> Result<(TokenStream, TokenStream)> { ) -> Result<(TokenStream, TokenStream)> {
if enum_has_fields(variants.iter()) { if enum_has_fields(variants.iter()) {
generate_checked_bit_pattern_enum_with_fields(input, variants) generate_checked_bit_pattern_enum_with_fields(input, variants, crate_name)
} else { } else {
generate_checked_bit_pattern_enum_without_fields(input, variants) generate_checked_bit_pattern_enum_without_fields(input, variants)
} }
@ -574,7 +574,7 @@ fn generate_checked_bit_pattern_enum_without_fields(
} }
fn generate_checked_bit_pattern_enum_with_fields( fn generate_checked_bit_pattern_enum_with_fields(
input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>, input: &DeriveInput, variants: &Punctuated<Variant, Token![,]>, crate_name: &TokenStream
) -> Result<(TokenStream, TokenStream)> { ) -> Result<(TokenStream, TokenStream)> {
let representation = get_repr(&input.attrs)?; let representation = get_repr(&input.attrs)?;
let vis = &input.vis; let vis = &input.vis;
@ -617,7 +617,7 @@ fn generate_checked_bit_pattern_enum_with_fields(
let fields = v.fields.iter().map(|v| &v.ty); let fields = v.fields.iter().map(|v| &v.ty);
quote! { quote! {
#[derive(::core::clone::Clone, ::core::marker::Copy, ::bytemuck::CheckedBitPattern)] #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::CheckedBitPattern)]
#[repr(C)] #[repr(C)]
#vis struct #variant_struct_ident(#(#fields),*); #vis struct #variant_struct_ident(#(#fields),*);
} }
@ -644,7 +644,7 @@ fn generate_checked_bit_pattern_enum_with_fields(
Ok(quote! { Ok(quote! {
#discriminant => { #discriminant => {
let payload = unsafe { &bits.payload.#ident }; let payload = unsafe { &bits.payload.#ident };
<#variant_struct_ident as ::bytemuck::CheckedBitPattern>::is_valid_bit_pattern(payload) <#variant_struct_ident as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(payload)
} }
}) })
}) })
@ -652,7 +652,7 @@ fn generate_checked_bit_pattern_enum_with_fields(
Ok(( Ok((
quote! { quote! {
#[derive(::core::clone::Clone, ::core::marker::Copy, ::bytemuck::AnyBitPattern)] #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::AnyBitPattern)]
#derive_dbg #derive_dbg
#bits_repr #bits_repr
#vis struct #bits_ty_ident { #vis struct #bits_ty_ident {
@ -660,7 +660,7 @@ fn generate_checked_bit_pattern_enum_with_fields(
payload: #variants_union_ident, payload: #variants_union_ident,
} }
#[derive(::core::clone::Clone, ::core::marker::Copy, ::bytemuck::AnyBitPattern)] #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::AnyBitPattern)]
#[repr(C)] #[repr(C)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
#vis union #variants_union_ident { #vis union #variants_union_ident {
@ -703,17 +703,17 @@ fn generate_checked_bit_pattern_enum_with_fields(
Ok(( Ok((
quote! { quote! {
#[derive(::core::clone::Clone, ::core::marker::Copy, ::bytemuck::CheckedBitPattern)] #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::CheckedBitPattern)]
#[repr(C)] #[repr(C)]
#vis struct #bits_ty(#(#fields),*); #vis struct #bits_ty(#(#fields),*);
}, },
quote! { quote! {
type Bits = <#bits_ty as ::bytemuck::CheckedBitPattern>::Bits; type Bits = <#bits_ty as #crate_name::CheckedBitPattern>::Bits;
#[inline] #[inline]
#[allow(clippy::double_comparisons)] #[allow(clippy::double_comparisons)]
fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
<#bits_ty as ::bytemuck::CheckedBitPattern>::is_valid_bit_pattern(bits) <#bits_ty as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(bits)
} }
}, },
)) ))
@ -740,7 +740,7 @@ fn generate_checked_bit_pattern_enum_with_fields(
// adding the discriminant repr integer as first field, as described above // adding the discriminant repr integer as first field, as described above
quote! { quote! {
#[derive(::core::clone::Clone, ::core::marker::Copy, ::bytemuck::CheckedBitPattern)] #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::CheckedBitPattern)]
#[repr(C)] #[repr(C)]
#vis struct #variant_struct_ident(#integer, #(#fields),*); #vis struct #variant_struct_ident(#integer, #(#fields),*);
} }
@ -767,7 +767,7 @@ fn generate_checked_bit_pattern_enum_with_fields(
Ok(quote! { Ok(quote! {
#discriminant => { #discriminant => {
let payload = unsafe { &bits.#ident }; let payload = unsafe { &bits.#ident };
<#variant_struct_ident as ::bytemuck::CheckedBitPattern>::is_valid_bit_pattern(payload) <#variant_struct_ident as #crate_name::CheckedBitPattern>::is_valid_bit_pattern(payload)
} }
}) })
}) })
@ -775,7 +775,7 @@ fn generate_checked_bit_pattern_enum_with_fields(
Ok(( Ok((
quote! { quote! {
#[derive(::core::clone::Clone, ::core::marker::Copy, ::bytemuck::AnyBitPattern)] #[derive(::core::clone::Clone, ::core::marker::Copy, #crate_name::AnyBitPattern)]
#bits_repr #bits_repr
#[allow(non_snake_case)] #[allow(non_snake_case)]
#vis union #bits_ty_ident { #vis union #bits_ty_ident {
@ -1219,3 +1219,47 @@ mod tests {
); );
} }
} }
pub fn bytemuck_crate_name(input: &DeriveInput) -> TokenStream {
const ATTR_NAME: &'static str = "crate";
let mut crate_name = quote!(::bytemuck);
for attr in &input.attrs {
if !attr.path().is_ident("bytemuck") {
continue;
}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident(ATTR_NAME) {
let expr: syn::Expr = meta.value()?.parse()?;
let mut value = &expr;
while let syn::Expr::Group(e) = value {
value = &e.expr;
}
if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit), ..
}) = value
{
let suffix = lit.suffix();
if !suffix.is_empty() {
bail!(format!("Unexpected suffix `{}` on string literal", suffix))
}
let path: syn::Path = match lit.parse() {
Ok(path) => path,
Err(_) => {
bail!(format!("Failed to parse path: {:?}", lit.value()))
}
};
crate_name = path.into_token_stream();
} else {
bail!(
"Expected bytemuck `crate` attribute to be a string: `crate = \"...\"`",
)
}
}
Ok(())
}).unwrap();
}
return crate_name;
}

View File

@ -443,3 +443,10 @@ fn checkedbitpattern_transparent_enum_with_fields() {
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C, align(16))] #[repr(C, align(16))]
struct Issue127 {} struct Issue127 {}
use bytemuck as reexport_name;
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, bytemuck::ByteEq)]
#[bytemuck(crate = "reexport_name")]
#[repr(C)]
struct Issue93 {}