@@ -179,17 +179,14 @@ use core::{
179
179
NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
180
180
} ,
181
181
ops:: { Deref , DerefMut } ,
182
- ptr, slice,
182
+ ptr:: { self , NonNull } ,
183
+ slice,
183
184
} ;
184
185
185
186
#[ cfg( feature = "alloc" ) ]
186
187
extern crate alloc;
187
188
#[ 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 } ;
193
190
194
191
// This is a hack to allow zerocopy-derive derives to work in this crate. They
195
192
// assume that zerocopy is linked as an extern crate, so they access items from
@@ -199,6 +196,237 @@ mod zerocopy {
199
196
pub ( crate ) use crate :: * ;
200
197
}
201
198
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
+
202
430
/// Types for which a sequence of bytes all set to zero represents a valid
203
431
/// instance of the type.
204
432
///
@@ -1153,6 +1381,7 @@ mod simd {
1153
1381
use core:: arch:: $arch:: { $( $typ) ,* } ;
1154
1382
1155
1383
use crate :: * ;
1384
+ impl_known_layout!( $( $typ) ,* ) ;
1156
1385
safety_comment! {
1157
1386
/// SAFETY:
1158
1387
/// See comment on module definition for justification.
@@ -2345,7 +2574,8 @@ where
2345
2574
}
2346
2575
}
2347
2576
2348
- trait AsAddress {
2577
+ #[ doc( hidden) ]
2578
+ pub trait AsAddress {
2349
2579
fn addr ( self ) -> usize ;
2350
2580
}
2351
2581
@@ -2659,7 +2889,8 @@ where
2659
2889
}
2660
2890
2661
2891
mod sealed {
2662
- pub trait Sealed { }
2892
+ pub trait ByteSliceSealed { }
2893
+ pub trait KnownLayoutSealed { }
2663
2894
}
2664
2895
2665
2896
// ByteSlice and ByteSliceMut abstract over [u8] references (&[u8], &mut [u8],
@@ -2685,7 +2916,9 @@ mod sealed {
2685
2916
///
2686
2917
/// [`Vec<u8>`]: alloc::vec::Vec
2687
2918
/// [`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
+ {
2689
2922
/// Gets a raw pointer to the first byte in the slice.
2690
2923
#[ inline]
2691
2924
fn as_ptr ( & self ) -> * const u8 {
@@ -2716,7 +2949,7 @@ pub unsafe trait ByteSliceMut: ByteSlice + DerefMut {
2716
2949
}
2717
2950
}
2718
2951
2719
- impl < ' a > sealed:: Sealed for & ' a [ u8 ] { }
2952
+ impl < ' a > sealed:: ByteSliceSealed for & ' a [ u8 ] { }
2720
2953
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2721
2954
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2722
2955
unsafe impl < ' a > ByteSlice for & ' a [ u8 ] {
@@ -2726,7 +2959,7 @@ unsafe impl<'a> ByteSlice for &'a [u8] {
2726
2959
}
2727
2960
}
2728
2961
2729
- impl < ' a > sealed:: Sealed for & ' a mut [ u8 ] { }
2962
+ impl < ' a > sealed:: ByteSliceSealed for & ' a mut [ u8 ] { }
2730
2963
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2731
2964
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2732
2965
unsafe impl < ' a > ByteSlice for & ' a mut [ u8 ] {
@@ -2736,7 +2969,7 @@ unsafe impl<'a> ByteSlice for &'a mut [u8] {
2736
2969
}
2737
2970
}
2738
2971
2739
- impl < ' a > sealed:: Sealed for cell:: Ref < ' a , [ u8 ] > { }
2972
+ impl < ' a > sealed:: ByteSliceSealed for cell:: Ref < ' a , [ u8 ] > { }
2740
2973
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2741
2974
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2742
2975
unsafe impl < ' a > ByteSlice for cell:: Ref < ' a , [ u8 ] > {
@@ -2746,7 +2979,7 @@ unsafe impl<'a> ByteSlice for cell::Ref<'a, [u8]> {
2746
2979
}
2747
2980
}
2748
2981
2749
- impl < ' a > sealed:: Sealed for RefMut < ' a , [ u8 ] > { }
2982
+ impl < ' a > sealed:: ByteSliceSealed for RefMut < ' a , [ u8 ] > { }
2750
2983
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
2751
2984
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2752
2985
unsafe impl < ' a > ByteSlice for RefMut < ' a , [ u8 ] > {
@@ -2764,6 +2997,63 @@ unsafe impl<'a> ByteSliceMut for &'a mut [u8] {}
2764
2997
#[ allow( clippy:: undocumented_unsafe_blocks) ]
2765
2998
unsafe impl < ' a > ByteSliceMut for RefMut < ' a , [ u8 ] > { }
2766
2999
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
+
2767
3057
#[ cfg( feature = "alloc" ) ]
2768
3058
mod alloc_support {
2769
3059
use alloc:: vec:: Vec ;
0 commit comments