@@ -117,3 +117,101 @@ impl fmt::Display for GenericFamily {
117
117
write ! ( f, "{}" , name)
118
118
}
119
119
}
120
+
121
+ // Safety: The enum is `repr(u8)` and has only fieldless variants.
122
+ unsafe impl bytemuck:: NoUninit for GenericFamily { }
123
+
124
+ // Safety: The enum is `repr(u8)` and `0` is a valid value.
125
+ unsafe impl bytemuck:: Zeroable for GenericFamily { }
126
+
127
+ // Safety: The enum is `repr(u8)`.
128
+ unsafe impl bytemuck:: checked:: CheckedBitPattern for GenericFamily {
129
+ type Bits = u8 ;
130
+
131
+ fn is_valid_bit_pattern ( bits : & u8 ) -> bool {
132
+ use bytemuck:: Contiguous ;
133
+ // Don't need to compare against MIN_VALUE as this is u8 and 0 is the MIN_VALUE.
134
+ * bits <= Self :: MAX_VALUE
135
+ }
136
+ }
137
+
138
+ // Safety: The enum is `repr(u8)`. All values are `u8` and fall within
139
+ // the min and max values.
140
+ unsafe impl bytemuck:: Contiguous for GenericFamily {
141
+ type Int = u8 ;
142
+ const MIN_VALUE : u8 = Self :: Serif as u8 ;
143
+ const MAX_VALUE : u8 = Self :: FangSong as u8 ;
144
+ }
145
+
146
+ #[ cfg( test) ]
147
+ mod tests {
148
+ use crate :: GenericFamily ;
149
+ use bytemuck:: { checked:: try_from_bytes, Contiguous , Zeroable } ;
150
+ use core:: ptr;
151
+
152
+ #[ test]
153
+ fn checked_bit_pattern ( ) {
154
+ let valid = bytemuck:: bytes_of ( & 2_u8 ) ;
155
+ let invalid = bytemuck:: bytes_of ( & 200_u8 ) ;
156
+
157
+ assert_eq ! (
158
+ Ok ( & GenericFamily :: Monospace ) ,
159
+ try_from_bytes:: <GenericFamily >( valid)
160
+ ) ;
161
+
162
+ assert ! ( try_from_bytes:: <GenericFamily >( invalid) . is_err( ) ) ;
163
+ }
164
+
165
+ #[ test]
166
+ fn contiguous ( ) {
167
+ let hd1 = GenericFamily :: SansSerif ;
168
+ let hd2 = GenericFamily :: from_integer ( hd1. into_integer ( ) ) ;
169
+ assert_eq ! ( Some ( hd1) , hd2) ;
170
+
171
+ assert_eq ! ( None , GenericFamily :: from_integer( 255 ) ) ;
172
+ }
173
+
174
+ #[ test]
175
+ fn zeroable ( ) {
176
+ let hd = GenericFamily :: zeroed ( ) ;
177
+ assert_eq ! ( hd, GenericFamily :: Serif ) ;
178
+ }
179
+
180
+ /// Tests that the [`Contiguous`] impl for [`GenericFamily`] is not trivially incorrect.
181
+ const _: ( ) = {
182
+ let mut value = 0 ;
183
+ while value <= GenericFamily :: MAX_VALUE {
184
+ // Safety: In a const context, therefore if this makes an invalid GenericFamily, that will be detected.
185
+ let it: GenericFamily = unsafe { ptr:: read ( ( & raw const value) . cast ( ) ) } ;
186
+ // Evaluate the enum value to ensure it actually has a valid tag
187
+ if it as u8 != value {
188
+ unreachable ! ( ) ;
189
+ }
190
+ value += 1 ;
191
+ }
192
+ } ;
193
+ }
194
+
195
+ #[ cfg( doctest) ]
196
+ /// Doctests aren't collected under `cfg(test)`; we can use `cfg(doctest)` instead
197
+ mod doctests {
198
+ /// Validates that any new variants in `GenericFamily` has led to a change in the `Contiguous` impl.
199
+ /// Note that to test this robustly, we'd need 256 tests, which is impractical.
200
+ /// We make the assumption that all new variants will maintain contiguousness.
201
+ ///
202
+ /// ```compile_fail,E0080
203
+ /// use bytemuck::Contiguous;
204
+ /// use styled_text::GenericFamily;
205
+ /// const {
206
+ /// let value = GenericFamily::MAX_VALUE + 1;
207
+ /// // Safety: In a const context, therefore if this makes an invalid GenericFamily, that will be detected.
208
+ /// // (Indeed, we rely upon that)
209
+ /// let it: GenericFamily = unsafe { core::ptr::read((&raw const value).cast()) };
210
+ /// // Evaluate the enum value to ensure it actually has an invalid tag
211
+ /// if it as u8 != value {
212
+ /// unreachable!();
213
+ /// }
214
+ /// }
215
+ /// ```
216
+ const _GENERIC_FAMILY: ( ) = { } ;
217
+ }
0 commit comments