@@ -179,17 +179,14 @@ use core::{
179179 NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
180180 } ,
181181 ops:: { Deref , DerefMut } ,
182- ptr, slice,
182+ ptr:: { self , NonNull } ,
183+ slice,
183184} ;
184185
185186#[ cfg( feature = "alloc" ) ]
186187extern crate alloc;
187188#[ cfg( feature = "alloc" ) ]
188- use {
189- alloc:: boxed:: Box ,
190- alloc:: vec:: Vec ,
191- core:: { alloc:: Layout , ptr:: NonNull } ,
192- } ;
189+ use { alloc:: boxed:: Box , alloc:: vec:: Vec , core:: alloc:: Layout } ;
193190
194191// This is a hack to allow zerocopy-derive derives to work in this crate. They
195192// assume that zerocopy is linked as an extern crate, so they access items from
@@ -199,6 +196,237 @@ mod zerocopy {
199196 pub ( crate ) use crate :: * ;
200197}
201198
199+ /// When performing a byte-slice-to-type cast, is the type taken from the prefix
200+ /// of the byte slice or from the suffix of the byte slice?
201+ #[ doc( hidden) ]
202+ #[ allow( missing_debug_implementations, missing_copy_implementations) ]
203+ pub enum CastType {
204+ Prefix ,
205+ Suffix ,
206+ }
207+
208+ /// A trait which carries information about a type's layout that is used by the
209+ /// internals of this crate.
210+ ///
211+ /// This trait is not meant for consumption by code outsie of this crate. While
212+ /// the normal semver stability guarantees apply with respect to which types
213+ /// implement this trait and which trait implementations are implied by this
214+ /// trait, no semver stability guarantees are made regarding its internals; they
215+ /// may change at any time, and code which makes use of them may break.
216+ ///
217+ /// # Safety
218+ ///
219+ /// This trait does not convey any safety guarantees to code outside this crate.
220+ pub unsafe trait KnownLayout : sealed:: KnownLayoutSealed {
221+ #[ doc( hidden) ]
222+ const FIXED_PREFIX_SIZE : usize ;
223+ #[ doc( hidden) ]
224+ const ALIGN : NonZeroUsize ;
225+ #[ doc( hidden) ]
226+ const TRAILING_SLICE_ELEM_SIZE : Option < usize > ;
227+
228+ /// Validates that the memory region at `addr` of length `bytes_len`
229+ /// satisfies `Self`'s size and alignment requirements, returning `(elems,
230+ /// split_at, prefix_suffix_bytes)`.
231+ ///
232+ /// In particular, `validate_size_align` validates that:
233+ /// - `bytes_len` is large enough to hold an instance of `Self`
234+ /// - If `cast_type` is `Prefix`, `addr` satisfies `Self`'s alignment
235+ /// requirements
236+ /// - If `cast_type` is `Suffix`, `addr + split_at` satisfies `Self`'s
237+ /// alignment requirements
238+ ///
239+ /// For DSTs, `elems` is the maximum number of trailing slice elements such
240+ /// that a `Self` with that number of trailing slice elements can fit in the
241+ /// provided space. For sized types, `elems` is always 0.
242+ ///
243+ /// `split_at` indicates the point at which to split the memory region in
244+ /// order to split it into the `Self` and the prefix or suffix. If
245+ /// `cast_type` is `Prefix`, `split_at` is the address of the first byte of
246+ /// the suffix. If `cast_type` is `Suffix`, `split_at` is the address of the
247+ /// first byte of the `Self`.
248+ ///
249+ /// # Panics
250+ ///
251+ /// Panics if called on a DST whose trailing slice element type is a
252+ /// zero-sized type.
253+ #[ doc( hidden) ]
254+ #[ inline( always) ]
255+ fn validate_size_align < A : AsAddress > (
256+ addr : A ,
257+ bytes_len : usize ,
258+ cast_type : CastType ,
259+ ) -> Option < ( usize , usize , usize ) > {
260+ let trailing_slice_bytes = bytes_len. checked_sub ( Self :: FIXED_PREFIX_SIZE ) ?;
261+ let ( elems, self_bytes) = if let Some ( elem_size) = Self :: TRAILING_SLICE_ELEM_SIZE {
262+ let elem_size = NonZeroUsize :: new ( elem_size)
263+ . expect ( "attempted to cast to slice type with zero-sized element" ) ;
264+ #[ allow( clippy:: arithmetic_side_effects) ]
265+ let elems = trailing_slice_bytes / elem_size;
266+ #[ allow( clippy:: arithmetic_side_effects) ]
267+ let self_bytes = Self :: FIXED_PREFIX_SIZE + ( elems * elem_size. get ( ) ) ;
268+ ( elems, self_bytes)
269+ } else {
270+ ( 0 , Self :: FIXED_PREFIX_SIZE )
271+ } ;
272+
273+ // `self_addr` indicates where in the given byte range the `Self` will
274+ // start. If we're doing a prefix cast, it starts at the beginning. If
275+ // we're doing a suffix cast, it starts after whatever bytes are
276+ // remaining.
277+ #[ allow( clippy:: arithmetic_side_effects) ]
278+ let ( self_addr, split_at) = match cast_type {
279+ CastType :: Prefix => ( addr. addr ( ) , self_bytes) ,
280+ CastType :: Suffix => {
281+ let split_at = bytes_len - self_bytes;
282+ ( addr. addr ( ) + split_at, split_at)
283+ }
284+ } ;
285+
286+ #[ allow( clippy:: arithmetic_side_effects) ]
287+ if self_addr % Self :: ALIGN != 0 {
288+ return None ;
289+ }
290+
291+ #[ allow( clippy:: arithmetic_side_effects) ]
292+ let ret = Some ( ( elems, split_at, bytes_len - self_bytes) ) ;
293+ ret
294+ }
295+
296+ /// SAFETY: The returned pointer has the same address and provenance as
297+ /// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems`
298+ /// elements in its trailing slice.
299+ #[ doc( hidden) ]
300+ fn raw_from_ptr_len ( bytes : NonNull < u8 > , elems : usize ) -> NonNull < Self > ;
301+ }
302+
303+ impl < T : KnownLayout > sealed:: KnownLayoutSealed for [ T ] { }
304+ // SAFETY: See inline comments.
305+ unsafe impl < T : KnownLayout > KnownLayout for [ T ] {
306+ // `[T]` is a slice type; it has no fields before the trailing slice.
307+ const FIXED_PREFIX_SIZE : usize = 0 ;
308+ // Slices have the same layout as the array they slice. [1] Arrays `[T; _]`
309+ // have the same alignment as `T`. [2]
310+ //
311+ // [1] https://doc.rust-lang.org/reference/type-layout.html#slice-layout
312+ // [2] https://doc.rust-lang.org/reference/type-layout.html#array-layout
313+ const ALIGN : NonZeroUsize = if let Some ( align) = NonZeroUsize :: new ( mem:: align_of :: < T > ( ) ) {
314+ align
315+ } else {
316+ unreachable ! ( )
317+ } ;
318+ const TRAILING_SLICE_ELEM_SIZE : Option < usize > = Some ( mem:: size_of :: < T > ( ) ) ;
319+
320+ // SAFETY: `.cast` preserves address and provenance. The returned pointer
321+ // refers to an object with `elems` elements by construction.
322+ #[ inline( always) ]
323+ fn raw_from_ptr_len ( data : NonNull < u8 > , elems : usize ) -> NonNull < Self > {
324+ // TODO(#67): Remove this allow. See NonNullExt for more details.
325+ #[ allow( unstable_name_collisions) ]
326+ NonNull :: slice_from_raw_parts ( data. cast :: < T > ( ) , elems)
327+ }
328+ }
329+
330+ /// Implements `KnownLayout` for a sized type.
331+ macro_rules! impl_known_layout {
332+ ( const $constvar: ident : $constty: ty, $tyvar: ident $( : ?$optbound: ident) ? => $ty: ty) => {
333+ impl_known_layout!( @inner const $constvar: $constty, $tyvar $( : ?$optbound) ? => $ty) ;
334+ } ;
335+ ( $tyvar: ident $( : ?$optbound: ident) ? => $ty: ty) => {
336+ impl_known_layout!( @inner , $tyvar $( : ?$optbound) ? => $ty) ;
337+ } ;
338+ ( $ty: ty) => {
339+ impl_known_layout!( @inner , => $ty) ;
340+ } ;
341+ ( $( $tyvar: ident $( : ?$optbound: ident) ? => $ty: ty) ,* ) => {
342+ $(
343+ impl_known_layout!( @inner , $tyvar $( : ?$optbound) ? => $ty) ;
344+ ) *
345+ } ;
346+ ( $( $ty: ty) ,* ) => {
347+ $(
348+ impl_known_layout!( @inner , => $ty) ;
349+ ) *
350+ } ;
351+ ( @inner $( const $constvar: ident : $constty: ty) ? , $( $tyvar: ident $( : ?$optbound: ident) ?) ? => $ty: ty) => {
352+ impl <$( const $constvar : $constty, ) ? $( $tyvar $( : ?$optbound) ?) ?> sealed:: KnownLayoutSealed for $ty { }
353+ // SAFETY: See inline comments.
354+ unsafe impl <$( const $constvar : $constty, ) ? $( $tyvar $( : ?$optbound) ?) ?> KnownLayout for $ty {
355+ const FIXED_PREFIX_SIZE : usize = mem:: size_of:: <$ty>( ) ;
356+ const ALIGN : NonZeroUsize = if let Some ( align) = NonZeroUsize :: new( mem:: align_of:: <$ty>( ) ) {
357+ align
358+ } else {
359+ unreachable!( )
360+ } ;
361+ // `T` is sized so it has no trailing slice.
362+ const TRAILING_SLICE_ELEM_SIZE : Option <usize > = None ;
363+
364+ // SAFETY: `.cast` preserves address and provenance.
365+ #[ inline( always) ]
366+ fn raw_from_ptr_len( bytes: NonNull <u8 >, _elems: usize ) -> NonNull <Self > {
367+ bytes. cast:: <Self >( )
368+ }
369+ }
370+ } ;
371+ }
372+
373+ /// Implements `KnownLayout` for a type in terms of the implementation of
374+ /// another type with the same representation.
375+ ///
376+ /// # Safety
377+ ///
378+ /// - `$ty` and `$repr` must have the same:
379+ /// - Fixed prefix size
380+ /// - Alignment
381+ /// - (For DSTs) trailing slice element size
382+ /// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`,
383+ /// and this operation must preserve referent size (ie, `size_of_val_raw`).
384+ macro_rules! unsafe_impl_known_layout {
385+ ( $( $tyvar: ident: ?Sized + KnownLayout =>) ? #[ repr( $repr: ty) ] $ty: ty) => {
386+ impl <$( $tyvar: ?Sized + KnownLayout ) ?> sealed:: KnownLayoutSealed for $ty { }
387+ unsafe impl <$( $tyvar: ?Sized + KnownLayout ) ?> KnownLayout for $ty {
388+ // SAFETY: Caller has promised that these values are the same for
389+ // `$ty` and `$repr`.
390+ const FIXED_PREFIX_SIZE : usize = <$repr as KnownLayout >:: FIXED_PREFIX_SIZE ;
391+ const ALIGN : NonZeroUsize = <$repr as KnownLayout >:: ALIGN ;
392+ const TRAILING_SLICE_ELEM_SIZE : Option <usize > = <$repr as KnownLayout >:: TRAILING_SLICE_ELEM_SIZE ;
393+
394+ // SAFETY: All operations preserve address and provenance. Caller
395+ // has promised that the `as` cast preserves size.
396+ #[ inline( always) ]
397+ fn raw_from_ptr_len( bytes: NonNull <u8 >, elems: usize ) -> NonNull <Self > {
398+ #[ allow( clippy:: as_conversions) ]
399+ let ptr = <$repr>:: raw_from_ptr_len( bytes, elems) . as_ptr( ) as * mut Self ;
400+ // SAFETY: `ptr` was converted from `bytes`, which is non-null.
401+ unsafe { NonNull :: new_unchecked( ptr) }
402+ }
403+ }
404+ } ;
405+ }
406+
407+ #[ rustfmt:: skip]
408+ impl_known_layout ! (
409+ ( ) ,
410+ u8 , i8 , u16 , i16 , u32 , i32 , u64 , i64 , u128 , i128 , usize , isize , f32 , f64 ,
411+ bool , char ,
412+ NonZeroU8 , NonZeroI8 , NonZeroU16 , NonZeroI16 , NonZeroU32 , NonZeroI32 ,
413+ NonZeroU64 , NonZeroI64 , NonZeroU128 , NonZeroI128 , NonZeroUsize , NonZeroIsize
414+ ) ;
415+ impl_known_layout ! ( T => Option <T >) ;
416+ impl_known_layout ! ( T : ?Sized => PhantomData <T >) ;
417+ impl_known_layout ! ( T => Wrapping <T >) ;
418+ impl_known_layout ! ( T => MaybeUninit <T >) ;
419+ impl_known_layout ! ( const N : usize , T => [ T ; N ] ) ;
420+
421+ safety_comment ! {
422+ /// SAFETY:
423+ /// `str` and `ManuallyDrop<[T]>` have the same representations as `[u8]`
424+ /// and `[T]` repsectively. `str` has different bit validity than `[u8]`,
425+ /// but that doesn't affect the soundness of this impl.
426+ unsafe_impl_known_layout!( #[ repr( [ u8 ] ) ] str ) ;
427+ unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T ) ] ManuallyDrop <T >) ;
428+ }
429+
202430/// Types for which a sequence of bytes all set to zero represents a valid
203431/// instance of the type.
204432///
@@ -1153,6 +1381,7 @@ mod simd {
11531381 use core:: arch:: $arch:: { $( $typ) ,* } ;
11541382
11551383 use crate :: * ;
1384+ impl_known_layout!( $( $typ) ,* ) ;
11561385 safety_comment! {
11571386 /// SAFETY:
11581387 /// See comment on module definition for justification.
@@ -2345,7 +2574,8 @@ where
23452574 }
23462575}
23472576
2348- trait AsAddress {
2577+ #[ doc( hidden) ]
2578+ pub trait AsAddress {
23492579 fn addr ( self ) -> usize ;
23502580}
23512581
@@ -2659,7 +2889,8 @@ where
26592889}
26602890
26612891mod sealed {
2662- pub trait Sealed { }
2892+ pub trait ByteSliceSealed { }
2893+ pub trait KnownLayoutSealed { }
26632894}
26642895
26652896// ByteSlice and ByteSliceMut abstract over [u8] references (&[u8], &mut [u8],
@@ -2685,7 +2916,9 @@ mod sealed {
26852916///
26862917/// [`Vec<u8>`]: alloc::vec::Vec
26872918/// [`split_at`]: crate::ByteSlice::split_at
2688- pub unsafe trait ByteSlice : Deref < Target = [ u8 ] > + Sized + self :: sealed:: Sealed {
2919+ pub unsafe trait ByteSlice :
2920+ Deref < Target = [ u8 ] > + Sized + self :: sealed:: ByteSliceSealed
2921+ {
26892922 /// Gets a raw pointer to the first byte in the slice.
26902923 #[ inline]
26912924 fn as_ptr ( & self ) -> * const u8 {
@@ -2716,7 +2949,7 @@ pub unsafe trait ByteSliceMut: ByteSlice + DerefMut {
27162949 }
27172950}
27182951
2719- impl < ' a > sealed:: Sealed for & ' a [ u8 ] { }
2952+ impl < ' a > sealed:: ByteSliceSealed for & ' a [ u8 ] { }
27202953// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
27212954#[ allow( clippy:: undocumented_unsafe_blocks) ]
27222955unsafe impl < ' a > ByteSlice for & ' a [ u8 ] {
@@ -2726,7 +2959,7 @@ unsafe impl<'a> ByteSlice for &'a [u8] {
27262959 }
27272960}
27282961
2729- impl < ' a > sealed:: Sealed for & ' a mut [ u8 ] { }
2962+ impl < ' a > sealed:: ByteSliceSealed for & ' a mut [ u8 ] { }
27302963// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
27312964#[ allow( clippy:: undocumented_unsafe_blocks) ]
27322965unsafe impl < ' a > ByteSlice for & ' a mut [ u8 ] {
@@ -2736,7 +2969,7 @@ unsafe impl<'a> ByteSlice for &'a mut [u8] {
27362969 }
27372970}
27382971
2739- impl < ' a > sealed:: Sealed for cell:: Ref < ' a , [ u8 ] > { }
2972+ impl < ' a > sealed:: ByteSliceSealed for cell:: Ref < ' a , [ u8 ] > { }
27402973// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
27412974#[ allow( clippy:: undocumented_unsafe_blocks) ]
27422975unsafe impl < ' a > ByteSlice for cell:: Ref < ' a , [ u8 ] > {
@@ -2746,7 +2979,7 @@ unsafe impl<'a> ByteSlice for cell::Ref<'a, [u8]> {
27462979 }
27472980}
27482981
2749- impl < ' a > sealed:: Sealed for RefMut < ' a , [ u8 ] > { }
2982+ impl < ' a > sealed:: ByteSliceSealed for RefMut < ' a , [ u8 ] > { }
27502983// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
27512984#[ allow( clippy:: undocumented_unsafe_blocks) ]
27522985unsafe impl < ' a > ByteSlice for RefMut < ' a , [ u8 ] > {
@@ -2764,6 +2997,63 @@ unsafe impl<'a> ByteSliceMut for &'a mut [u8] {}
27642997#[ allow( clippy:: undocumented_unsafe_blocks) ]
27652998unsafe impl < ' a > ByteSliceMut for RefMut < ' a , [ u8 ] > { }
27662999
3000+ // A polyfill for `<*const _>::cast_mut` that we can use before our MSRV is
3001+ // 1.65, when that method was stabilized.
3002+
3003+ // TODO(#67): Once our MSRV is 1.65, remove this.
3004+ trait RawPtrExt {
3005+ type Mut ;
3006+ fn cast_mut ( self ) -> Self :: Mut ;
3007+ }
3008+
3009+ impl < T : ?Sized > RawPtrExt for * const T {
3010+ type Mut = * mut T ;
3011+ #[ allow( clippy:: as_conversions) ]
3012+ #[ inline( always) ]
3013+ fn cast_mut ( self ) -> * mut T {
3014+ self as * mut T
3015+ }
3016+ }
3017+
3018+ // A polyfill for `<*mut _>::cast_const` that we can use before our MSRV is
3019+ // 1.65, when that method was stabilized.
3020+ //
3021+ // TODO(#67): Once our MSRV is 1.65, remove this.
3022+ trait RawMutPtrExt {
3023+ type Const ;
3024+ fn cast_const ( self ) -> Self :: Const ;
3025+ }
3026+
3027+ impl < T : ?Sized > RawMutPtrExt for * mut T {
3028+ type Const = * const T ;
3029+ #[ allow( clippy:: as_conversions) ]
3030+ #[ inline( always) ]
3031+ fn cast_const ( self ) -> * const T {
3032+ self as * const T
3033+ }
3034+ }
3035+
3036+ // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our
3037+ // MSRV is 1.70, when that function was stabilized.
3038+ //
3039+ // TODO(#67): Once our MSRV is 1.70, remove this.
3040+ trait NonNullExt {
3041+ type SliceOfSelf ;
3042+
3043+ fn slice_from_raw_parts ( data : Self , len : usize ) -> Self :: SliceOfSelf ;
3044+ }
3045+
3046+ impl < T > NonNullExt for NonNull < T > {
3047+ type SliceOfSelf = NonNull < [ T ] > ;
3048+
3049+ #[ inline( always) ]
3050+ fn slice_from_raw_parts ( data : Self , len : usize ) -> NonNull < [ T ] > {
3051+ let ptr = ptr:: slice_from_raw_parts_mut ( data. as_ptr ( ) , len) ;
3052+ // SAFETY: `ptr` is converted from `data`, which is non-null.
3053+ unsafe { NonNull :: new_unchecked ( ptr) }
3054+ }
3055+ }
3056+
27673057#[ cfg( feature = "alloc" ) ]
27683058mod alloc_support {
27693059 use alloc:: vec:: Vec ;
0 commit comments