Skip to content

Commit

Permalink
[derive] Automatically derive super-traits
Browse files Browse the repository at this point in the history
`#[derive(FromBytes)]` implies `#[derive(FromZeros)]`, which implies
`#[derive(TryFromBytes)]`.

Closes #925
  • Loading branch information
joshlf committed Feb 23, 2024
1 parent ca49473 commit 02662fa
Show file tree
Hide file tree
Showing 14 changed files with 58 additions and 65 deletions.
6 changes: 3 additions & 3 deletions src/byteorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
//!
//! ```rust,edition2021
//! # #[cfg(feature = "derive")] { // This example uses derives, and won't compile without them
//! use zerocopy::{IntoBytes, ByteSlice, FromBytes, FromZeros, NoCell, Ref, Unaligned};
//! use zerocopy::{IntoBytes, ByteSlice, FromBytes, NoCell, Ref, Unaligned};
//! use zerocopy::byteorder::network_endian::U16;
//!
//! #[derive(FromZeros, FromBytes, IntoBytes, NoCell, Unaligned)]
//! #[derive(FromBytes, IntoBytes, NoCell, Unaligned)]
//! #[repr(C)]
//! struct UdpHeader {
//! src_port: U16,
Expand Down Expand Up @@ -357,7 +357,7 @@ example of how it can be used for parsing UDP packets.
[`IntoBytes`]: crate::IntoBytes
[`Unaligned`]: crate::Unaligned"),
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(any(feature = "derive", test), derive(KnownLayout, NoCell, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned))]
#[cfg_attr(any(feature = "derive", test), derive(KnownLayout, NoCell, FromBytes, IntoBytes, Unaligned))]
#[repr(transparent)]
pub struct $name<O>([u8; $bytes], PhantomData<O>);
}
Expand Down
12 changes: 5 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5766,9 +5766,7 @@ mod tests {
//
// This is used to test the custom derives of our traits. The `[u8]` type
// gets a hand-rolled impl, so it doesn't exercise our custom derives.
#[derive(
Debug, Eq, PartialEq, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, NoCell,
)]
#[derive(Debug, Eq, PartialEq, FromBytes, IntoBytes, Unaligned, NoCell)]
#[repr(transparent)]
struct Unsized([u8]);

Expand Down Expand Up @@ -7896,7 +7894,7 @@ mod tests {
assert_eq!(too_many_bytes[0], 123);
}

#[derive(Debug, Eq, PartialEq, TryFromBytes, FromZeros, FromBytes, IntoBytes, NoCell)]
#[derive(Debug, Eq, PartialEq, FromBytes, IntoBytes, NoCell)]
#[repr(C)]
struct Foo {
a: u32,
Expand Down Expand Up @@ -7925,7 +7923,7 @@ mod tests {

#[test]
fn test_array() {
#[derive(TryFromBytes, FromZeros, FromBytes, IntoBytes, NoCell)]
#[derive(FromBytes, IntoBytes, NoCell)]
#[repr(C)]
struct Foo {
a: [u16; 33],
Expand Down Expand Up @@ -7989,7 +7987,7 @@ mod tests {

#[test]
fn test_transparent_packed_generic_struct() {
#[derive(IntoBytes, TryFromBytes, FromZeros, FromBytes, Unaligned)]
#[derive(IntoBytes, FromBytes, Unaligned)]
#[repr(transparent)]
struct Foo<T> {
_t: T,
Expand All @@ -7999,7 +7997,7 @@ mod tests {
assert_impl_all!(Foo<u32>: FromZeros, FromBytes, IntoBytes);
assert_impl_all!(Foo<u8>: Unaligned);

#[derive(IntoBytes, TryFromBytes, FromZeros, FromBytes, Unaligned)]
#[derive(IntoBytes, FromBytes, Unaligned)]
#[repr(packed)]
struct Bar<T, U> {
_t: T,
Expand Down
6 changes: 1 addition & 5 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,6 @@ pub(crate) mod testutil {
#[derive(
KnownLayout,
NoCell,
TryFromBytes,
FromZeros,
FromBytes,
IntoBytes,
Eq,
Expand Down Expand Up @@ -249,9 +247,7 @@ pub(crate) mod testutil {
}
}

#[derive(
NoCell, FromZeros, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
)]
#[derive(NoCell, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone)]
#[repr(C)]
pub(crate) struct Nested<T, U: ?Sized> {
_t: T,
Expand Down
2 changes: 1 addition & 1 deletion src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use super::*;
#[derive(Default, Copy)]
#[cfg_attr(
any(feature = "derive", test),
derive(NoCell, KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned)
derive(NoCell, KnownLayout, FromBytes, IntoBytes, Unaligned)
)]
#[repr(C, packed)]
pub struct Unalign<T>(T);
Expand Down
16 changes: 12 additions & 4 deletions zerocopy-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,17 @@ pub fn derive_try_from_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenSt

#[proc_macro_derive(FromZeros)]
pub fn derive_from_zeros(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
let try_from_bytes = derive_try_from_bytes(ts.clone());

let ast = syn::parse_macro_input!(ts as DeriveInput);
match &ast.data {
let from_zeros = match &ast.data {
Data::Struct(strct) => derive_from_zeros_struct(&ast, strct),
Data::Enum(enm) => derive_from_zeros_enum(&ast, enm),
Data::Union(unn) => derive_from_zeros_union(&ast, unn),
}
.into()
.into();

IntoIterator::into_iter([try_from_bytes, from_zeros]).collect()
}

/// Deprecated: prefer [`FromZeros`] instead.
Expand All @@ -314,13 +318,17 @@ pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStrea

#[proc_macro_derive(FromBytes)]
pub fn derive_from_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
let from_zeros = derive_from_zeros(ts.clone());

let ast = syn::parse_macro_input!(ts as DeriveInput);
match &ast.data {
let from_bytes = match &ast.data {
Data::Struct(strct) => derive_from_bytes_struct(&ast, strct),
Data::Enum(enm) => derive_from_bytes_enum(&ast, enm),
Data::Union(unn) => derive_from_bytes_union(&ast, unn),
}
.into()
.into();

IntoIterator::into_iter([from_zeros, from_bytes]).collect()
}

#[proc_macro_derive(IntoBytes)]
Expand Down
12 changes: 6 additions & 6 deletions zerocopy-derive/tests/enum_from_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ include!("include.rs");
// `Variant128` has a discriminant of -128) since Rust won't automatically wrap
// a signed discriminant around without you explicitly telling it to.

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(u8)]
enum FooU8 {
Variant0,
Expand Down Expand Up @@ -292,7 +292,7 @@ enum FooU8 {

util_assert_impl_all!(FooU8: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(i8)]
enum FooI8 {
Variant0,
Expand Down Expand Up @@ -555,7 +555,7 @@ enum FooI8 {

util_assert_impl_all!(FooI8: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(u8, align(2))]
enum FooU8Align {
Variant0,
Expand Down Expand Up @@ -818,7 +818,7 @@ enum FooU8Align {

util_assert_impl_all!(FooU8Align: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(i8, align(2))]
enum FooI8Align {
Variant0,
Expand Down Expand Up @@ -1081,7 +1081,7 @@ enum FooI8Align {

util_assert_impl_all!(FooI8Align: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(u16)]
enum FooU16 {
Variant0,
Expand Down Expand Up @@ -66624,7 +66624,7 @@ enum FooU16 {

util_assert_impl_all!(FooU16: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(i16)]
enum FooI16 {
Variant0,
Expand Down
9 changes: 1 addition & 8 deletions zerocopy-derive/tests/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,7 @@ include!("include.rs");

extern crate zerocopy as _zerocopy;

// #[macro_use]
// mod util;

// use std::{marker::PhantomData, option::IntoIter};

#[derive(
_zerocopy::KnownLayout, _zerocopy::FromZeros, _zerocopy::FromBytes, _zerocopy::Unaligned,
)]
#[derive(_zerocopy::KnownLayout, _zerocopy::FromBytes, _zerocopy::Unaligned)]
#[repr(C)]
struct TypeParams<'a, T, I: imp::Iterator> {
a: T,
Expand Down
2 changes: 0 additions & 2 deletions zerocopy-derive/tests/include.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ pub mod util {
#[derive(
super::imp::KnownLayout,
super::imp::NoCell,
super::imp::TryFromBytes,
super::imp::FromZeros,
super::imp::FromBytes,
super::imp::IntoBytes,
Copy,
Expand Down
6 changes: 3 additions & 3 deletions zerocopy-derive/tests/paths_and_modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ include!("include.rs");
mod foo {
use super::*;

#[derive(imp::FromZeros, imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[repr(C)]
pub struct Foo {
foo: u8,
}

#[derive(imp::FromZeros, imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[repr(C)]
pub struct Bar {
bar: u8,
Expand All @@ -32,7 +32,7 @@ mod foo {

use foo::Foo;

#[derive(imp::FromZeros, imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[repr(C)]
struct Baz {
foo: Foo,
Expand Down
12 changes: 6 additions & 6 deletions zerocopy-derive/tests/struct_from_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,34 @@ include!("include.rs");
// A struct is `FromBytes` if:
// - all fields are `FromBytes`

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
struct Zst;

util_assert_impl_all!(Zst: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
struct One {
a: u8,
}

util_assert_impl_all!(One: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
struct Two {
a: u8,
b: Zst,
}

util_assert_impl_all!(Two: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
struct Unsized {
a: [u8],
}

util_assert_impl_all!(Unsized: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
struct TypeParams<'a, T: ?imp::Sized, I: imp::Iterator> {
a: I::Item,
b: u8,
Expand All @@ -58,7 +58,7 @@ util_assert_impl_all!(TypeParams<'static, [util::AU16], imp::IntoIter<()>>: imp:

// Deriving `FromBytes` should work if the struct has bounded parameters.

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(transparent)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::FromBytes, const N: usize>(
[T; N],
Expand Down
10 changes: 5 additions & 5 deletions zerocopy-derive/tests/struct_try_from_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn zst() {
imp::assert!(is_bit_valid);
}

#[derive(imp::TryFromBytes, imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(C)]
struct One {
a: u8,
Expand All @@ -45,7 +45,7 @@ fn one() {
imp::assert!(is_bit_valid);
}

#[derive(imp::TryFromBytes, imp::FromZeros)]
#[derive(imp::FromZeros)]
#[repr(C)]
struct Two {
a: bool,
Expand Down Expand Up @@ -88,7 +88,7 @@ fn two_bad() {
imp::assert!(!is_bit_valid);
}

#[derive(imp::TryFromBytes, imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(C)]
struct Unsized {
a: [u8],
Expand Down Expand Up @@ -119,7 +119,7 @@ fn un_sized() {
imp::assert!(is_bit_valid);
}

#[derive(imp::TryFromBytes, imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(C)]
struct TypeParams<'a, T: ?imp::Sized, I: imp::Iterator> {
a: I::Item,
Expand All @@ -136,7 +136,7 @@ util_assert_impl_all!(TypeParams<'static, [util::AU16], imp::IntoIter<()>>: imp:

// Deriving `imp::TryFromBytes` should work if the struct has bounded parameters.

#[derive(imp::TryFromBytes, imp::FromZeros, imp::FromBytes)]
#[derive(imp::FromBytes)]
#[repr(transparent)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::TryFromBytes, const N: usize>(
imp::PhantomData<&'a &'b ()>,
Expand Down
10 changes: 5 additions & 5 deletions zerocopy-derive/tests/union_from_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@ include!("include.rs");
// A union is `imp::FromBytes` if:
// - all fields are `imp::FromBytes`

#[derive(Clone, Copy, imp::FromZeros, imp::FromBytes)]
#[derive(Clone, Copy, imp::NoCell, imp::FromBytes)]
union Zst {
a: (),
}

util_assert_impl_all!(Zst: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::NoCell, imp::FromBytes)]
union One {
a: u8,
}

util_assert_impl_all!(One: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::NoCell, imp::FromBytes)]
union Two {
a: u8,
b: Zst,
}

util_assert_impl_all!(Two: imp::FromBytes);

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::NoCell, imp::FromBytes)]
union TypeParams<'a, T: imp::Copy, I: imp::Iterator>
where
I::Item: imp::Copy,
Expand All @@ -54,7 +54,7 @@ util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::FromBytes

// Deriving `imp::FromBytes` should work if the union has bounded parameters.

#[derive(imp::FromZeros, imp::FromBytes)]
#[derive(imp::NoCell, imp::FromBytes)]
#[repr(C)]
union WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::FromBytes, const N: usize>
where
Expand Down
Loading

0 comments on commit 02662fa

Please sign in to comment.