Skip to content

Commit

Permalink
Make TryFromBytes a super-trait of FromZeros (#952)
Browse files Browse the repository at this point in the history
Makes progress on #5

Closes #962

Co-authored-by: Jack Wrenn <[email protected]>
  • Loading branch information
joshlf and jswrenn committed Feb 29, 2024
1 parent 5465e6e commit 26de2d3
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 14 deletions.
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@ pub unsafe trait TryFromBytes {
doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html"),
doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html#analysis"),
)]
pub unsafe trait FromZeros {
pub unsafe trait FromZeros: TryFromBytes {
// The `Self: Sized` bound makes it so that `FromZeros` is still object
// safe.
#[doc(hidden)]
Expand Down Expand Up @@ -3774,8 +3774,10 @@ safety_comment! {
///
/// `UnsafeCell<T>`` has the same in-memory representation as its inner
/// type `T`.
unsafe_impl!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>);
unsafe_impl!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>);
///
/// TODO(#5): Implement `FromZeros` and `FromBytes` when `T: ?Sized`.
unsafe_impl!(T: FromZeros => FromZeros for UnsafeCell<T>);
unsafe_impl!(T: FromBytes => FromBytes for UnsafeCell<T>);
unsafe_impl!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>);
unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
Expand Down Expand Up @@ -7001,7 +7003,6 @@ mod tests {
#[test]
fn test_object_safety() {
fn _takes_no_cell(_: &dyn NoCell) {}
fn _takes_from_zeros(_: &dyn FromZeros) {}
fn _takes_unaligned(_: &dyn Unaligned) {}
}

Expand Down
30 changes: 20 additions & 10 deletions zerocopy-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,12 @@ fn derive_try_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_m
}

// A union is `TryFromBytes` if:
// - any of its fields are `TryFromBytes`
// - all of its fields are `TryFromBytes` and `NoCell`

fn derive_try_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream {
let self_type_trait_bounds = SelfBounds::All(&[Trait::NoCell]);
// TODO(#5): Remove the `NoCell` bound.
let field_type_trait_bounds =
FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::NoCell)]);
let extras = Some({
let fields = unn.fields();
let field_names = fields.iter().map(|(name, _ty)| name);
Expand Down Expand Up @@ -434,8 +436,8 @@ fn derive_try_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro
ast,
unn,
Trait::TryFromBytes,
FieldBounds::ALL_SELF,
self_type_trait_bounds,
field_type_trait_bounds,
SelfBounds::None,
None,
extras,
)
Expand Down Expand Up @@ -606,11 +608,15 @@ fn derive_from_zeros_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::Tok
impl_block(ast, enm, Trait::FromZeros, FieldBounds::ALL_SELF, SelfBounds::None, None, None)
}

// Like structs, unions are `FromZeros` if
// - all fields are `FromZeros`
// Unions are `FromZeros` if
// - all fields are `FromZeros` and `NoCell`

fn derive_from_zeros_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream {
impl_block(ast, unn, Trait::FromZeros, FieldBounds::ALL_SELF, SelfBounds::None, None, None)
// TODO(#5): Remove the `NoCell` bound. It's only necessary for
// compatibility with `derive(TryFromBytes)` on unions; not for soundness.
let field_type_trait_bounds =
FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::NoCell)]);
impl_block(ast, unn, Trait::FromZeros, field_type_trait_bounds, SelfBounds::None, None, None)
}

// A struct is `FromBytes` if:
Expand Down Expand Up @@ -692,11 +698,15 @@ const ENUM_FROM_BYTES_CFG: Config<EnumRepr> = {
}
};

// Like structs, unions are `FromBytes` if
// - all fields are `FromBytes`
// Unions are `FromBytes` if
// - all fields are `FromBytes` and `NoCell`

fn derive_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream {
impl_block(ast, unn, Trait::FromBytes, FieldBounds::ALL_SELF, SelfBounds::None, None, None)
// TODO(#5): Remove the `NoCell` bound. It's only necessary for
// compatibility with `derive(TryFromBytes)` on unions; not for soundness.
let field_type_trait_bounds =
FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::NoCell)]);
impl_block(ast, unn, Trait::FromBytes, field_type_trait_bounds, SelfBounds::None, None, None)
}

fn derive_into_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream {
Expand Down

0 comments on commit 26de2d3

Please sign in to comment.