@@ -157,6 +157,8 @@ use core::{
157
157
ptr, slice,
158
158
} ;
159
159
160
+ use project:: Projectable ;
161
+
160
162
#[ cfg( feature = "alloc" ) ]
161
163
extern crate alloc;
162
164
#[ cfg( feature = "alloc" ) ]
@@ -174,6 +176,29 @@ mod zerocopy {
174
176
pub ( crate ) use crate :: * ;
175
177
}
176
178
179
+ /// Documents multiple unsafe blocks with a single safety comment.
180
+ ///
181
+ /// Invoked as:
182
+ ///
183
+ /// ```rust,ignore
184
+ /// safety_comment! {
185
+ /// // Non-doc comments come first.
186
+ /// /// SAFETY:
187
+ /// /// Safety comment starts on its own line.
188
+ /// macro_1!(args);
189
+ /// macro_2! { args };
190
+ /// }
191
+ /// ```
192
+ ///
193
+ /// The macro invocations are emitted, each decorated with the following
194
+ /// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`.
195
+ macro_rules! safety_comment {
196
+ ( #[ doc = r" SAFETY:" ] $( #[ doc = $_doc: literal] ) * $( $macro: ident!$args: tt; ) * ) => {
197
+ #[ allow( clippy:: undocumented_unsafe_blocks) ]
198
+ const _: ( ) = { $( $macro!$args; ) * } ;
199
+ }
200
+ }
201
+
177
202
/// Types for which a sequence of bytes all set to zero represents a valid
178
203
/// instance of the type.
179
204
///
@@ -499,6 +524,291 @@ pub unsafe trait FromBytes: FromZeroes {
499
524
}
500
525
}
501
526
527
+ /// TODO
528
+ ///
529
+ /// # Safety
530
+ ///
531
+ /// `AsMaybeUninit` must only be implemented for types which are `Sized` or
532
+ /// whose last field is a slice whose element type is `Sized` (this includes
533
+ /// slice types themselves; in a slice type, the "last field" simply refers to
534
+ /// the slice itself).
535
+ pub unsafe trait AsMaybeUninit {
536
+ /// TODO
537
+ ///
538
+ /// # Safety
539
+ ///
540
+ /// For `T: AsMaybeUninit`, the following must hold:
541
+ /// - Given `m: T::MaybeUninit`, it is sound to write uninitialized bytes at
542
+ /// every byte offset in `m` (this description avoids the "what lengths
543
+ /// are valid" problem)
544
+ /// - `T` and `T::MaybeUninit` have the same alignment requirement (can't
545
+ /// use `align_of` to describe this because it requires that its argument
546
+ /// is sized)
547
+ /// - `T` and `T::MaybeUninit` are either both `Sized` or both `!Sized`
548
+ /// - If they are `Sized`, `size_of::<T>() == size_of::<T::MaybeUninit>()`
549
+ /// - If they are `!Sized`, then they are both DSTs with a trailing slice.
550
+ /// Given `t: &T` and `m: &T::MaybeUninit` with the same number of
551
+ /// elements in their trailing slices, `size_of_val(t) == size_of_val(m)`.
552
+ type MaybeUninit : ?Sized + FromBytes ;
553
+ }
554
+
555
+ unsafe impl < T : Sized > AsMaybeUninit for T {
556
+ type MaybeUninit = MaybeUninit < T > ;
557
+ }
558
+
559
+ unsafe impl < T : Sized > AsMaybeUninit for [ T ] {
560
+ type MaybeUninit = [ MaybeUninit < T > ] ;
561
+ }
562
+
563
+ unsafe impl AsMaybeUninit for str {
564
+ type MaybeUninit = <[ u8 ] as AsMaybeUninit >:: MaybeUninit ;
565
+ }
566
+
567
+ /// A value which might or might not constitute a valid instance of `T`.
568
+ ///
569
+ /// `MaybeValid<T>` has the same layout (size and alignment) and field offsets
570
+ /// as `T`. However, it may contain any bit pattern with a few restrictions:
571
+ /// Given `m: MaybeValid<T>` and a byte offset, `b` in the range `[0,
572
+ /// size_of::<MaybeValid<T>>())`:
573
+ /// - If, in all valid instances `t: T`, the byte at offset `b` in `t` is
574
+ /// initialized, then the byte at offset `b` within `m` is guaranteed to be
575
+ /// initialized.
576
+ /// - Let `s` be the sequence of bytes of length `b` in the offset range `[0,
577
+ /// b)` in `m`. Let `TT` be the subset of valid instances of `T` which contain
578
+ /// this sequence in the offset range `[0, b)`. If, for all instances of `t:
579
+ /// T` in `TT`, the byte at offset `b` in `t` is initialized, then the byte at
580
+ /// offset `b` in `m` is guaranteed to be initialized.
581
+ ///
582
+ /// Pragmatically, this means that if `m` is guaranteed to contain an enum
583
+ /// type at a particular offset, and the enum discriminant stored in `m`
584
+ /// corresponds to a valid variant of that enum type, then it is guaranteed
585
+ /// that the appropriate bytes of `m` are initialized as defined by that
586
+ /// variant's layout (although note that the variant's layout may contain
587
+ /// another enum type, in which case the same rules apply depending on the
588
+ /// state of its discriminant, and so on recursively).
589
+ ///
590
+ /// # Safety
591
+ ///
592
+ /// TODO (make sure to mention enum layout)
593
+ #[ derive( FromZeroes , FromBytes , AsBytes , Unaligned ) ]
594
+ #[ repr( transparent) ]
595
+ pub struct MaybeValid < T : AsMaybeUninit + ?Sized > {
596
+ inner : T :: MaybeUninit ,
597
+ }
598
+
599
+ impl < T > MaybeValid < T > {
600
+ /// TODO
601
+ pub const unsafe fn assume_valid ( self ) -> T {
602
+ unsafe { self . inner . assume_init ( ) }
603
+ }
604
+ }
605
+
606
+ impl < T > MaybeValid < [ T ] > {
607
+ /// TODO
608
+ pub const fn as_slice_of_maybe_valids ( & self ) -> & [ MaybeValid < T > ] {
609
+ let inner: & [ <T as AsMaybeUninit >:: MaybeUninit ] = & self . inner ;
610
+ // SAFETY: Since `inner` is a `&[T::MaybeUninit]`, and `MaybeValid<T>`
611
+ // is a `repr(transparent)` struct around `T::MaybeUninit`, `inner` has
612
+ // the same layout as `&[MaybeValid<T>]`.
613
+ unsafe { mem:: transmute ( inner) }
614
+ }
615
+ }
616
+
617
+ impl < const N : usize , T > MaybeValid < [ T ; N ] > {
618
+ /// TODO
619
+ pub const fn as_slice ( & self ) -> & MaybeValid < [ T ] > {
620
+ todo ! ( )
621
+ }
622
+ }
623
+
624
+ unsafe impl < T , F > Projectable < F , MaybeValid < F > > for MaybeValid < T > {
625
+ type Inner = T ;
626
+ }
627
+
628
+ impl < T > Debug for MaybeValid < T > {
629
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
630
+ f. pad ( core:: any:: type_name :: < Self > ( ) )
631
+ }
632
+ }
633
+
634
+ /// TODO
635
+ pub unsafe trait TryFromBytes : AsMaybeUninit {
636
+ /// TODO
637
+ fn is_bit_valid ( candidate : & MaybeValid < Self > ) -> bool ;
638
+
639
+ /// TODO
640
+ // Note that, in a future in which we distinguish between `FromBytes` and `RefFromBytes`,
641
+ // this requires `where Self: RefFromBytes` to disallow interior mutability.
642
+ fn try_from_ref ( bytes : & [ u8 ] ) -> Option < & Self >
643
+ where
644
+ // TODO: Remove this bound.
645
+ Self : Sized ,
646
+ {
647
+ // TODO(https://github.com/rust-lang/rust/issues/115080): Inline this
648
+ // function once #115080 is resolved.
649
+ #[ inline( always) ]
650
+ fn try_read_from_inner < T : Sized , F : FnOnce ( & MaybeValid < T > ) -> bool > (
651
+ bytes : & [ u8 ] ,
652
+ is_bit_valid : F ,
653
+ ) -> Option < & T > {
654
+ let maybe_valid = Ref :: < _ , MaybeValid < T > > :: new ( bytes) ?. into_ref ( ) ;
655
+
656
+ if is_bit_valid ( maybe_valid) {
657
+ Some ( unsafe { & * bytes. as_ptr ( ) . cast :: < T > ( ) } )
658
+ } else {
659
+ None
660
+ }
661
+ }
662
+
663
+ try_read_from_inner ( bytes, Self :: is_bit_valid)
664
+ }
665
+
666
+ /// TODO
667
+ fn try_from_mut ( bytes : & mut [ u8 ] ) -> Option < & mut Self >
668
+ where
669
+ // TODO: Remove the `Sized` bound.
670
+ Self : AsBytes + Sized ,
671
+ {
672
+ // TODO(https://github.com/rust-lang/rust/issues/115080): Inline this
673
+ // function once #115080 is resolved.
674
+ #[ inline( always) ]
675
+ fn try_read_from_mut_inner < T : Sized , F : FnOnce ( & MaybeValid < T > ) -> bool > (
676
+ bytes : & mut [ u8 ] ,
677
+ is_bit_valid : F ,
678
+ ) -> Option < & mut T > {
679
+ let maybe_valid = Ref :: < _ , MaybeValid < T > > :: new ( & * bytes) ?. into_ref ( ) ;
680
+
681
+ if is_bit_valid ( maybe_valid) {
682
+ Some ( unsafe { & mut * bytes. as_mut_ptr ( ) . cast :: < T > ( ) } )
683
+ } else {
684
+ None
685
+ }
686
+ }
687
+
688
+ try_read_from_mut_inner ( bytes, Self :: is_bit_valid)
689
+ }
690
+
691
+ /// TODO
692
+ fn try_read_from ( bytes : & [ u8 ] ) -> Option < Self >
693
+ where
694
+ Self : Sized ,
695
+ {
696
+ // TODO(https://github.com/rust-lang/rust/issues/115080): Inline this
697
+ // function once #115080 is resolved.
698
+ #[ inline( always) ]
699
+ fn try_read_from_inner < T : Sized , F : FnOnce ( & MaybeValid < T > ) -> bool > (
700
+ bytes : & [ u8 ] ,
701
+ is_bit_valid : F ,
702
+ ) -> Option < T > {
703
+ let maybe_valid = MaybeValid :: < T > :: read_from ( bytes) ?;
704
+
705
+ if is_bit_valid ( & maybe_valid) {
706
+ Some ( unsafe { maybe_valid. assume_valid ( ) } )
707
+ } else {
708
+ None
709
+ }
710
+ }
711
+
712
+ try_read_from_inner ( bytes, Self :: is_bit_valid)
713
+ }
714
+ }
715
+
716
+ unsafe impl < T : FromBytes > TryFromBytes for T {
717
+ fn is_bit_valid ( _candidate : & MaybeValid < T > ) -> bool {
718
+ true
719
+ }
720
+ }
721
+
722
+ // TODO: This conflicts with the blanket impl for `T: TryFromBytes`.
723
+
724
+ // unsafe impl<const N: usize, T: TryFromBytes + Sized> TryFromBytes for [T; N]
725
+ // where
726
+ // // TODO: Why can't Rust infer this based on the blanket impl for `T: Sized`?
727
+ // // It sets `MaybeUninit = MaybeUninit<T>`, which is `Sized`.
728
+ // <T as AsMaybeUninit>::MaybeUninit: Sized,
729
+ // {
730
+ // fn is_bit_valid(candidate: &MaybeValid<[T; N]>) -> bool {
731
+ // candidate.as_slice().as_slice_of_maybe_valids().iter().all(|c| T::is_bit_valid(c))
732
+ // }
733
+ // }
734
+
735
+ unsafe impl < T : TryFromBytes + Sized > TryFromBytes for [ T ]
736
+ where
737
+ // TODO: Why can't Rust infer this based on the blanket impl for `T: Sized`?
738
+ // It sets `MaybeUninit = MaybeUninit<T>`, which is `Sized`.
739
+ <T as AsMaybeUninit >:: MaybeUninit : Sized ,
740
+ {
741
+ fn is_bit_valid ( candidate : & MaybeValid < [ T ] > ) -> bool {
742
+ candidate. as_slice_of_maybe_valids ( ) . iter ( ) . all ( |c| T :: is_bit_valid ( c) )
743
+ }
744
+ }
745
+
746
+ /// # Safety
747
+ ///
748
+ /// It must be sound to transmute `&MaybeValid<$ty>` into `&$repr`.
749
+ macro_rules! unsafe_impl_try_from_bytes {
750
+ ( $ty: ty, $repr: ty, |$candidate: ident| $is_bit_valid: expr) => {
751
+ unsafe impl TryFromBytes for $ty {
752
+ fn is_bit_valid( candidate: & MaybeValid <$ty>) -> bool {
753
+ let $candidate = unsafe { & * ( candidate as * const MaybeValid <$ty> as * const $repr) } ;
754
+ $is_bit_valid
755
+ }
756
+ }
757
+ } ;
758
+ }
759
+
760
+ safety_comment ! {
761
+ /// SAFETY:
762
+ /// All of the `NonZeroXxx` types have the same layout as `Xxx`. Also, every
763
+ /// byte of such a type is required to be initialized, so it is guaranteed
764
+ /// that every byte of a `MaybeValid<NonZeroXxx>` must also be initialized.
765
+ /// Thus, it is sound to transmute a `&MaybeValid<NonZeroXxx>` to a `&Xxx`.
766
+ ///
767
+ /// TODO: Why are these impls correct (ie, ensure valid NonZeroXxx types)?
768
+ unsafe_impl_try_from_bytes!( NonZeroU8 , u8 , |n| * n != 0 ) ;
769
+ unsafe_impl_try_from_bytes!( NonZeroU16 , u16 , |n| * n != 0 ) ;
770
+ unsafe_impl_try_from_bytes!( NonZeroU32 , u32 , |n| * n != 0 ) ;
771
+ unsafe_impl_try_from_bytes!( NonZeroU64 , u64 , |n| * n != 0 ) ;
772
+ unsafe_impl_try_from_bytes!( NonZeroU128 , u128 , |n| * n != 0 ) ;
773
+ unsafe_impl_try_from_bytes!( NonZeroUsize , usize , |n| * n != 0 ) ;
774
+ unsafe_impl_try_from_bytes!( NonZeroI8 , i8 , |n| * n != 0 ) ;
775
+ unsafe_impl_try_from_bytes!( NonZeroI16 , i16 , |n| * n != 0 ) ;
776
+ unsafe_impl_try_from_bytes!( NonZeroI32 , i32 , |n| * n != 0 ) ;
777
+ unsafe_impl_try_from_bytes!( NonZeroI64 , i64 , |n| * n != 0 ) ;
778
+ unsafe_impl_try_from_bytes!( NonZeroI128 , i128 , |n| * n != 0 ) ;
779
+ unsafe_impl_try_from_bytes!( NonZeroIsize , isize , |n| * n != 0 ) ;
780
+ }
781
+
782
+ unsafe_impl_try_from_bytes ! ( bool , u8 , |byte| * byte < 2 ) ;
783
+
784
+ unsafe_impl_try_from_bytes ! ( char , [ u8 ; 4 ] , |bytes| {
785
+ let c = u32 :: from_ne_bytes( * bytes) ;
786
+ char :: from_u32( c) . is_some( )
787
+ } ) ;
788
+
789
+ unsafe_impl_try_from_bytes ! ( str , [ u8 ] , |bytes| core:: str :: from_utf8( bytes) . is_ok( ) ) ;
790
+
791
+ mod try_from_bytes_derive_example {
792
+ use super :: * ;
793
+
794
+ struct Foo {
795
+ a : u8 ,
796
+ b : u16 ,
797
+ }
798
+
799
+ impl_try_from_bytes ! ( Foo { a: u8 , b: u16 } ) ;
800
+
801
+ struct Bar ( Foo ) ;
802
+
803
+ impl Bar {
804
+ fn is_valid ( & self ) -> bool {
805
+ u16:: from ( self . 0 . a ) < self . 0 . b
806
+ }
807
+ }
808
+
809
+ impl_try_from_bytes ! ( Bar { 0 : Foo } => is_valid) ;
810
+ }
811
+
502
812
/// Types which are safe to treat as an immutable byte slice.
503
813
///
504
814
/// WARNING: Do not implement this trait yourself! Instead, use
@@ -696,29 +1006,6 @@ pub unsafe trait Unaligned {
696
1006
Self : Sized ;
697
1007
}
698
1008
699
- /// Documents multiple unsafe blocks with a single safety comment.
700
- ///
701
- /// Invoked as:
702
- ///
703
- /// ```rust,ignore
704
- /// safety_comment! {
705
- /// // Non-doc comments come first.
706
- /// /// SAFETY:
707
- /// /// Safety comment starts on its own line.
708
- /// macro_1!(args);
709
- /// macro_2! { args };
710
- /// }
711
- /// ```
712
- ///
713
- /// The macro invocations are emitted, each decorated with the following
714
- /// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`.
715
- macro_rules! safety_comment {
716
- ( #[ doc = r" SAFETY:" ] $( #[ doc = $_doc: literal] ) * $( $macro: ident!$args: tt; ) * ) => {
717
- #[ allow( clippy:: undocumented_unsafe_blocks) ]
718
- const _: ( ) = { $( $macro!$args; ) * } ;
719
- }
720
- }
721
-
722
1009
/// Unsafely implements trait(s) for a type.
723
1010
macro_rules! unsafe_impl {
724
1011
// Implement `$trait` for `$ty` with no bounds.
0 commit comments