@@ -62,3 +62,62 @@ macro_rules! union_has_padding {
6262 false $( || core:: mem:: size_of:: <$t>( ) != core:: mem:: size_of:: <$ts>( ) ) *
6363 } ;
6464}
65+
66+ /// Implements `TryFromBytes` for a struct type by delegating to existing
67+ /// implementations for each of its fields, and optionally supports a custom
68+ /// validation method.
69+ ///
70+ /// ```rust
71+ /// # use zerocopy::impl_try_from_bytes_for_struct;
72+ ///
73+ /// #[repr(C)]
74+ /// struct Foo {
75+ /// a: u8,
76+ /// b: u16,
77+ /// }
78+ ///
79+ /// impl_try_from_bytes_for_struct!(Foo { a: u8, b: u16 });
80+ ///
81+ /// #[repr(transparent)]
82+ /// struct Bar(Foo);
83+ ///
84+ /// impl Bar {
85+ /// fn is_valid(&self) -> bool {
86+ /// u16::from(self.0.a) < self.0.b
87+ /// }
88+ /// }
89+ ///
90+ /// impl_try_from_bytes_for_struct!(Bar { 0: Foo } => is_valid);
91+ /// ```
92+ ///
93+ /// # Safety
94+ ///
95+ /// `$ty` must be a struct type, `$f` must list every field's name, and `$f_ty`
96+ /// must be the correct types for those fields.
97+ #[ doc( hidden) ] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
98+ #[ macro_export]
99+ macro_rules! impl_try_from_bytes_for_struct {
100+ ( $ty: ty { $( $f: tt: $f_ty: ty) ,* } $( => $validation_method: ident) ?) => {
101+ // SAFETY: The caller promises that all fields are listed with their
102+ // correct types. We validate that every field is valid, which is the
103+ // only requirement for the entire struct to be valid. Thus, we
104+ // correctly implement `is_bit_valid` as required by the trait's safety
105+ // documentation.
106+ #[ allow( unused_qualifications) ]
107+ unsafe impl zerocopy:: TryFromBytes for $ty {
108+ fn is_bit_valid( bytes: & zerocopy:: MaybeValid <Self >) -> bool {
109+ true $( && {
110+ let f: & zerocopy:: MaybeValid <$f_ty> = zerocopy:: project!( & bytes. $f) ;
111+ zerocopy:: TryFromBytes :: is_bit_valid( f)
112+ } ) *
113+ $( && {
114+ // SAFETY: We just validated that all of the struct's fields
115+ // are valid, which means that the struct itself is valid.
116+ // That is the only precondition of `assume_valid_ref`.
117+ let slf = unsafe { bytes. assume_valid_ref( ) } ;
118+ slf. $validation_method( )
119+ } ) ?
120+ }
121+ }
122+ }
123+ }
0 commit comments