Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,9 @@ const _: () = {
// private field, and because it is the name it is referred to in the public
// documentation of `ManuallyDrop::new`, `ManuallyDrop::into_inner`,
// `ManuallyDrop::take` and `ManuallyDrop::drop`.
unsafe impl<T> HasField<value, 0, { crate::ident_id!(value) }> for ManuallyDrop<T> {
unsafe impl<T> HasField<value, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!(value) }>
for ManuallyDrop<T>
{
type Type = T;

#[inline]
Expand Down
21 changes: 18 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,17 @@ const _: () = unsafe {
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T::MaybeUninit)] MaybeUninit<T>)
};

// FIXME(#196, #2856): Eventually, we'll want to support enums variants and
// union fields being treated uniformly since they behave similarly to each
// other in terms of projecting validity – specifically, for a type `T` with
// validity `V`, if `T` is a struct type, then its fields straightforwardly also
// have validity `V`. By contrast, if `T` is an enum or union type, then
// validity is not straightforwardly recursive in this way.
#[doc(hidden)]
pub const STRUCT_VARIANT_ID: i128 = -1;
#[doc(hidden)]
pub const UNION_VARIANT_ID: i128 = -2;

/// Projects a given field from `Self`.
///
/// All implementations of `HasField` for a particular field `f` in `Self`
Expand All @@ -1099,12 +1110,16 @@ const _: () = unsafe {
///
/// A field `f` is `HasField` for `Self` if and only if:
///
/// - if `f` has name `n`, `FIELD_ID` is `zerocopy::ident_id!(n)`; otherwise, if
/// `f` is at index `i`, `FIELD_ID` is `zerocopy::ident_id!(i)`.
/// - If `Self` is a struct or union type, then `VARIANT_ID` is
/// `STRUCT_VARIANT_ID` or `UNION_VARIANT_ID` respectively; otherwise, if
/// `Self` is an enum type, `VARIANT_ID` is the numerical index of the enum
/// variant in which `f` appears.
/// - If `f` has name `n`, `FIELD_ID` is `zerocopy::ident_id!(n)`; otherwise,
/// if `f` is at index `i`, `FIELD_ID` is `zerocopy::ident_id!(i)`.
/// - `Field` is a type with the same visibility as `f`.
/// - `Type` has the same type as `f`.
#[doc(hidden)]
pub unsafe trait HasField<Field, const VARIANT_ID: u128, const FIELD_ID: u128> {
pub unsafe trait HasField<Field, const VARIANT_ID: i128, const FIELD_ID: i128> {
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized;
Expand Down
2 changes: 1 addition & 1 deletion src/pointer/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ impl<'a, T: ?Sized> PtrInner<'a, T> {
/// Projects a field.
#[must_use]
#[inline(always)]
pub fn project<F, const VARIANT_ID: u128, const FIELD_ID: u128>(self) -> PtrInner<'a, T::Type>
pub fn project<F, const VARIANT_ID: i128, const FIELD_ID: i128>(self) -> PtrInner<'a, T::Type>
where
T: HasField<F, VARIANT_ID, FIELD_ID>,
{
Expand Down
6 changes: 3 additions & 3 deletions src/util/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ macro_rules! ident_id {
#[inline(always)]
#[must_use]
#[allow(clippy::as_conversions, clippy::indexing_slicing, clippy::arithmetic_side_effects)]
pub const fn hash_name(name: &str) -> u128 {
pub const fn hash_name(name: &str) -> i128 {
let name = name.as_bytes();

// We guarantee freedom from hash collisions between any two strings of
Expand All @@ -569,7 +569,7 @@ pub const fn hash_name(name: &str) -> u128 {
i += 1;
}

return u128::from_ne_bytes(bytes);
return i128::from_ne_bytes(bytes);
};

// An implementation of FxHasher, although returning a u128. Probably
Expand All @@ -584,7 +584,7 @@ pub const fn hash_name(name: &str) -> u128 {
hash = (hash.rotate_left(5) ^ (name[i] as u128)).wrapping_mul(K);
i += 1;
}
hash
i128::from_ne_bytes(hash.to_ne_bytes())
}

/// Is a given source a valid instance of `Dst`?
Expand Down
10 changes: 5 additions & 5 deletions zerocopy-derive/src/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,10 @@ pub(crate) fn derive_is_bit_valid(
// `___ZerocopyRawEnum` has the same layout as `Self`.
let slf = unsafe { slf.cast::<___ZerocopyRawEnum #ty_generics>() };

slf.project::<_, 0, { #zerocopy_crate::ident_id!(variants) }>()
.project::<_, 0, { #zerocopy_crate::ident_id!(#variants_union_field_ident) }>()
.project::<_, 0, { #zerocopy_crate::ident_id!(value) }>()
.project::<_, 0, { #zerocopy_crate::ident_id!(#variant_struct_field_index) }>()
slf.project::<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(variants) }>()
.project::<_, { #zerocopy_crate::UNION_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variants_union_field_ident) }>()
.project::<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(value) }>()
.project::<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variant_struct_field_index) }>()
}
})
.build()
Expand Down Expand Up @@ -455,7 +455,7 @@ pub(crate) fn derive_is_bit_valid(
// overall struct.
let project = #zerocopy_crate::pointer::PtrInner::project::<
_,
0,
{ #zerocopy_crate::STRUCT_VARIANT_ID },
{ #zerocopy_crate::ident_id!(variants) }
>;
let variants = unsafe {
Expand Down
23 changes: 18 additions & 5 deletions zerocopy-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,14 +758,19 @@ fn derive_has_field_struct_union(
)
});

let has_fields = fields.iter().map(|(_, ident, ty)| {
let variant_id: Box<Expr> = match &ast.data {
Data::Struct(_) => parse_quote!({ #zerocopy_crate::STRUCT_VARIANT_ID }),
Data::Union(_) => parse_quote!({ #zerocopy_crate::UNION_VARIANT_ID }),
_ => unreachable!(),
};

let has_fields = fields.iter().map(move |(_, ident, ty)| {
let field_token = Ident::new(&format!("ẕ{}", ident), ident.span());
ImplBlockBuilder::new(
ast,
data,
Trait::HasField {
// Use `0` to denote the sole 'variant' of structs and unions.
variant_id: parse_quote!({ #zerocopy_crate::ident_id!(0) }),
variant_id: variant_id.clone(),
field: parse_quote!(#field_token),
field_id: parse_quote!({ #zerocopy_crate::ident_id!(#ident) }),
},
Expand Down Expand Up @@ -844,7 +849,11 @@ fn derive_try_from_bytes_struct(
use #zerocopy_crate::pointer::PtrInner;

true #(&& {
let project = <Self as #zerocopy_crate::HasField<_, 0, { #zerocopy_crate::ident_id!(#field_names) }>>::project;
let project = <Self as #zerocopy_crate::HasField<
_,
{ #zerocopy_crate::STRUCT_VARIANT_ID },
{ #zerocopy_crate::ident_id!(#field_names) }
>>::project;
// SAFETY:
// - `project` is a field projection, and so it
// addresses a subset of the bytes addressed by `slf`
Expand Down Expand Up @@ -905,7 +914,11 @@ fn derive_try_from_bytes_union(
use #zerocopy_crate::pointer::PtrInner;

false #(|| {
let project = <Self as #zerocopy_crate::HasField<_, 0, { #zerocopy_crate::ident_id!(#field_names) }>>::project;
let project = <Self as #zerocopy_crate::HasField<
_,
{ #zerocopy_crate::UNION_VARIANT_ID },
{ #zerocopy_crate::ident_id!(#field_names) }
>>::project;
// SAFETY:
// - `project` is a field projection, and so it
// addresses a subset of the bytes addressed by `slf`
Expand Down
Loading
Loading