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