@@ -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