@@ -173,6 +173,7 @@ pub use crate::wrappers::*;
173
173
pub use zerocopy_derive:: * ;
174
174
175
175
use core:: {
176
+ alloc:: Layout ,
176
177
cell:: { self , RefMut } ,
177
178
cmp:: Ordering ,
178
179
fmt:: { self , Debug , Display , Formatter } ,
@@ -191,9 +192,8 @@ use core::{
191
192
extern crate alloc;
192
193
#[ cfg( feature = "alloc" ) ]
193
194
use {
194
- alloc:: boxed:: Box ,
195
- alloc:: vec:: Vec ,
196
- core:: { alloc:: Layout , ptr:: NonNull } ,
195
+ alloc:: { boxed:: Box , vec:: Vec } ,
196
+ core:: ptr:: NonNull ,
197
197
} ;
198
198
199
199
// This is a hack to allow zerocopy-derive derives to work in this crate. They
@@ -204,6 +204,105 @@ mod zerocopy {
204
204
pub ( crate ) use crate :: * ;
205
205
}
206
206
207
+ /// The layout of a type which might be dynamically-sized.
208
+ ///
209
+ /// `DstLayout` describes the layout of sized types, slice types, and "custom
210
+ /// DSTs" - ie, those that are known by the type system to have a trailing slice
211
+ /// (as distinguished from `dyn Trait` types - such types *might* have a
212
+ /// trailing slice type, but the type system isn't aware of it).
213
+ #[ doc( hidden) ]
214
+ #[ allow( missing_debug_implementations, missing_copy_implementations) ]
215
+ #[ cfg_attr( test, derive( Debug , PartialEq , Eq ) ) ]
216
+ pub struct DstLayout {
217
+ /// The base size and the alignment of the type:
218
+ /// - For sized types, the size encoded by this `Layout` is
219
+ /// `size_of::<T>()`. For DSTs, the size represents the size of the type
220
+ /// when the trailing slice field contains 0 elements.
221
+ /// - For all types, the alignment represents the alignment of the type.
222
+ _base_layout : Layout ,
223
+ /// For sized types, `None`. For DSTs, the size of the element type of the
224
+ /// trailing slice.
225
+ _trailing_slice_elem_size : Option < usize > ,
226
+ }
227
+
228
+ impl DstLayout {
229
+ /// Constructs a `DstLayout` which describes `T`.
230
+ ///
231
+ /// # Safety
232
+ ///
233
+ /// Unsafe code may assume that `DstLayout` is the correct layout for `T`.
234
+ const fn for_type < T > ( ) -> DstLayout {
235
+ DstLayout { _base_layout : Layout :: new :: < T > ( ) , _trailing_slice_elem_size : None }
236
+ }
237
+
238
+ /// Constructs a `DstLayout` which describes `[T]`.
239
+ ///
240
+ /// # Safety
241
+ ///
242
+ /// Unsafe code may assume that `DstLayout` is the correct layout for `[T]`.
243
+ const fn for_slice < T > ( ) -> DstLayout {
244
+ DstLayout {
245
+ // SAFETY: `[T; 0]` has the same alignment as `T`, but zero size.
246
+ // [1] A slice of length 0 has no size, so 0 is the correct size for
247
+ // the base of the type.
248
+ //
249
+ // [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout
250
+ _base_layout : Layout :: new :: < [ T ; 0 ] > ( ) ,
251
+ _trailing_slice_elem_size : Some ( mem:: size_of :: < T > ( ) ) ,
252
+ }
253
+ }
254
+ }
255
+
256
+ /// A trait which carries information about a type's layout that is used by the
257
+ /// internals of this crate.
258
+ ///
259
+ /// This trait is not meant for consumption by code outside of this crate. While
260
+ /// the normal semver stability guarantees apply with respect to which types
261
+ /// implement this trait and which trait implementations are implied by this
262
+ /// trait, no semver stability guarantees are made regarding its internals; they
263
+ /// may change at any time, and code which makes use of them may break.
264
+ ///
265
+ /// # Safety
266
+ ///
267
+ /// This trait does not convey any safety guarantees to code outside this crate.
268
+ #[ doc( hidden) ] // TODO: Remove this once KnownLayout is used by other APIs
269
+ pub unsafe trait KnownLayout : sealed:: KnownLayoutSealed {
270
+ #[ doc( hidden) ]
271
+ const LAYOUT : DstLayout ;
272
+ }
273
+
274
+ impl < T : KnownLayout > sealed:: KnownLayoutSealed for [ T ] { }
275
+ // SAFETY: Delegates safety to `DstLayout::for_slice`.
276
+ unsafe impl < T : KnownLayout > KnownLayout for [ T ] {
277
+ const LAYOUT : DstLayout = DstLayout :: for_slice :: < T > ( ) ;
278
+ }
279
+
280
+ #[ rustfmt:: skip]
281
+ impl_known_layout ! (
282
+ ( ) ,
283
+ u8 , i8 , u16 , i16 , u32 , i32 , u64 , i64 , u128 , i128 , usize , isize , f32 , f64 ,
284
+ bool , char ,
285
+ NonZeroU8 , NonZeroI8 , NonZeroU16 , NonZeroI16 , NonZeroU32 , NonZeroI32 ,
286
+ NonZeroU64 , NonZeroI64 , NonZeroU128 , NonZeroI128 , NonZeroUsize , NonZeroIsize
287
+ ) ;
288
+ #[ rustfmt:: skip]
289
+ impl_known_layout ! (
290
+ T => Option <T >,
291
+ T : ?Sized => PhantomData <T >,
292
+ T => Wrapping <T >,
293
+ T => MaybeUninit <T >,
294
+ ) ;
295
+ impl_known_layout ! ( const N : usize , T => [ T ; N ] ) ;
296
+
297
+ safety_comment ! {
298
+ /// SAFETY:
299
+ /// `str` and `ManuallyDrop<[T]>` have the same representations as `[u8]`
300
+ /// and `[T]` repsectively. `str` has different bit validity than `[u8]`,
301
+ /// but that doesn't affect the soundness of this impl.
302
+ unsafe_impl_known_layout!( #[ repr( [ u8 ] ) ] str ) ;
303
+ unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T ) ] ManuallyDrop <T >) ;
304
+ }
305
+
207
306
/// Types for which a sequence of bytes all set to zero represents a valid
208
307
/// instance of the type.
209
308
///
@@ -1171,6 +1270,7 @@ mod simd {
1171
1270
use core:: arch:: $arch:: { $( $typ) ,* } ;
1172
1271
1173
1272
use crate :: * ;
1273
+ impl_known_layout!( $( $typ) ,* ) ;
1174
1274
safety_comment! {
1175
1275
/// SAFETY:
1176
1276
/// See comment on module definition for justification.
@@ -2279,7 +2379,8 @@ where
2279
2379
}
2280
2380
2281
2381
mod sealed {
2282
- pub trait Sealed { }
2382
+ pub trait ByteSliceSealed { }
2383
+ pub trait KnownLayoutSealed { }
2283
2384
}
2284
2385
2285
2386
// ByteSlice and ByteSliceMut abstract over [u8] references (&[u8], &mut [u8],
@@ -2305,7 +2406,9 @@ mod sealed {
2305
2406
///
2306
2407
/// [`Vec<u8>`]: alloc::vec::Vec
2307
2408
/// [`split_at`]: crate::ByteSlice::split_at
2308
- pub unsafe trait ByteSlice : Deref < Target = [ u8 ] > + Sized + self :: sealed:: Sealed {
2409
+ pub unsafe trait ByteSlice :
2410
+ Deref < Target = [ u8 ] > + Sized + self :: sealed:: ByteSliceSealed
2411
+ {
2309
2412
/// Gets a raw pointer to the first byte in the slice.
2310
2413
#[ inline]
2311
2414
fn as_ptr ( & self ) -> * const u8 {
@@ -2336,7 +2439,7 @@ pub unsafe trait ByteSliceMut: ByteSlice + DerefMut {
2336
2439
}
2337
2440
}
2338
2441
2339
- impl < ' a > sealed:: Sealed for & ' a [ u8 ] { }
2442
+ impl < ' a > sealed:: ByteSliceSealed for & ' a [ u8 ] { }
2340
2443
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2341
2444
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2342
2445
unsafe impl < ' a > ByteSlice for & ' a [ u8 ] {
@@ -2346,7 +2449,7 @@ unsafe impl<'a> ByteSlice for &'a [u8] {
2346
2449
}
2347
2450
}
2348
2451
2349
- impl < ' a > sealed:: Sealed for & ' a mut [ u8 ] { }
2452
+ impl < ' a > sealed:: ByteSliceSealed for & ' a mut [ u8 ] { }
2350
2453
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2351
2454
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2352
2455
unsafe impl < ' a > ByteSlice for & ' a mut [ u8 ] {
@@ -2356,7 +2459,7 @@ unsafe impl<'a> ByteSlice for &'a mut [u8] {
2356
2459
}
2357
2460
}
2358
2461
2359
- impl < ' a > sealed:: Sealed for cell:: Ref < ' a , [ u8 ] > { }
2462
+ impl < ' a > sealed:: ByteSliceSealed for cell:: Ref < ' a , [ u8 ] > { }
2360
2463
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2361
2464
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2362
2465
unsafe impl < ' a > ByteSlice for cell:: Ref < ' a , [ u8 ] > {
@@ -2366,7 +2469,7 @@ unsafe impl<'a> ByteSlice for cell::Ref<'a, [u8]> {
2366
2469
}
2367
2470
}
2368
2471
2369
- impl < ' a > sealed:: Sealed for RefMut < ' a , [ u8 ] > { }
2472
+ impl < ' a > sealed:: ByteSliceSealed for RefMut < ' a , [ u8 ] > { }
2370
2473
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2371
2474
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2372
2475
unsafe impl < ' a > ByteSlice for RefMut < ' a , [ u8 ] > {
@@ -2635,6 +2738,39 @@ mod tests {
2635
2738
}
2636
2739
}
2637
2740
2741
+ #[ test]
2742
+ fn test_known_layout ( ) {
2743
+ // Test that `$ty` and `ManuallyDrop<$ty>` have the expected layout.
2744
+ // Test that `PhantomData<$ty>` has the same layout as `()` regardless
2745
+ // of `$ty`.
2746
+ macro_rules! test {
2747
+ ( $ty: ty, $expect: expr) => {
2748
+ let expect = $expect;
2749
+ assert_eq!( <$ty as KnownLayout >:: LAYOUT , expect) ;
2750
+ assert_eq!( <ManuallyDrop <$ty> as KnownLayout >:: LAYOUT , expect) ;
2751
+ assert_eq!( <PhantomData <$ty> as KnownLayout >:: LAYOUT , <( ) as KnownLayout >:: LAYOUT ) ;
2752
+ } ;
2753
+ }
2754
+
2755
+ let layout = |base_size, align, _trailing_slice_elem_size| DstLayout {
2756
+ _base_layout : Layout :: from_size_align ( base_size, align) . unwrap ( ) ,
2757
+ _trailing_slice_elem_size,
2758
+ } ;
2759
+
2760
+ test ! ( ( ) , layout( 0 , 1 , None ) ) ;
2761
+ test ! ( u8 , layout( 1 , 1 , None ) ) ;
2762
+ // Use `align_of` because `u64` alignment may be smaller than 8 on some
2763
+ // platforms.
2764
+ test ! ( u64 , layout( 8 , mem:: align_of:: <u64 >( ) , None ) ) ;
2765
+ test ! ( AU64 , layout( 8 , 8 , None ) ) ;
2766
+
2767
+ test ! ( Option <& ' static ( ) >, usize :: LAYOUT ) ;
2768
+
2769
+ test ! ( [ ( ) ] , layout( 0 , 1 , Some ( 0 ) ) ) ;
2770
+ test ! ( [ u8 ] , layout( 0 , 1 , Some ( 1 ) ) ) ;
2771
+ test ! ( str , layout( 0 , 1 , Some ( 1 ) ) ) ;
2772
+ }
2773
+
2638
2774
#[ test]
2639
2775
fn test_object_safety ( ) {
2640
2776
fn _takes_from_zeroes ( _: & dyn FromZeroes ) { }
0 commit comments