@@ -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,275 @@ 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
+ // TODO: Why can't Rust infer this based on the blanket impl for `T:
647
+ // Sized`? It sets `MaybeUninit = MaybeUninit<T>`, which is `Sized`.
648
+ <Self as AsMaybeUninit >:: MaybeUninit : Sized ,
649
+ {
650
+ // let byte_array: &ByteArray<Self> = TryFrom::try_from(bytes).ok()?;
651
+ // let aligned = Align::try_from_ref(byte_array)?;
652
+ let maybe_valid = Ref :: < _ , MaybeValid < Self > > :: new ( bytes) ?. into_ref ( ) ;
653
+
654
+ if Self :: is_bit_valid ( maybe_valid) {
655
+ Some ( unsafe { & * bytes. as_ptr ( ) . cast :: < Self > ( ) } )
656
+ } else {
657
+ None
658
+ }
659
+ }
660
+
661
+ /// TODO
662
+ fn try_from_mut ( bytes : & mut [ u8 ] ) -> Option < & mut Self >
663
+ where
664
+ // TODO: Remove the `Sized` bound.
665
+ Self : AsBytes + Sized ,
666
+ // TODO: Why can't Rust infer this based on the blanket impl for `T:
667
+ // Sized`? It sets `MaybeUninit = MaybeUninit<T>`, which is `Sized`.
668
+ <Self as AsMaybeUninit >:: MaybeUninit : Sized ,
669
+ {
670
+ // let byte_array: &ByteArray<Self> = TryFrom::try_from(&*bytes).ok()?;
671
+ // let aligned = Align::try_from_ref(byte_array)?;
672
+ let maybe_valid = Ref :: < _ , MaybeValid < Self > > :: new ( & * bytes) ?. into_ref ( ) ;
673
+
674
+ if Self :: is_bit_valid ( maybe_valid) {
675
+ Some ( unsafe { & mut * bytes. as_mut_ptr ( ) . cast :: < Self > ( ) } )
676
+ } else {
677
+ None
678
+ }
679
+ }
680
+
681
+ /// TODO
682
+ fn try_read_from ( bytes : & [ u8 ] ) -> Option < Self >
683
+ where
684
+ Self : Sized ,
685
+ // TODO: Why can't Rust infer this based on the blanket impl for `T:
686
+ // Sized`? It sets `MaybeUninit = MaybeUninit<T>`, which is `Sized`.
687
+ <Self as AsMaybeUninit >:: MaybeUninit : Sized ,
688
+ {
689
+ // let byte_array: &ByteArray<Self> = TryFrom::try_from(bytes).ok()?;
690
+ let maybe_valid = MaybeValid :: < Self > :: read_from ( bytes) ?;
691
+
692
+ if Self :: is_bit_valid ( & maybe_valid) {
693
+ Some ( unsafe { maybe_valid. assume_valid ( ) } )
694
+ } else {
695
+ None
696
+ }
697
+ }
698
+ }
699
+
700
+ unsafe impl < T : FromBytes > TryFromBytes for T {
701
+ fn is_bit_valid ( _candidate : & MaybeValid < T > ) -> bool {
702
+ true
703
+ }
704
+ }
705
+
706
+ // TODO: This conflicts with the blanket impl for `T: TryFromBytes`.
707
+
708
+ // unsafe impl<const N: usize, T: TryFromBytes + Sized> TryFromBytes for [T; N]
709
+ // where
710
+ // // TODO: Why can't Rust infer this based on the blanket impl for `T: Sized`?
711
+ // // It sets `MaybeUninit = MaybeUninit<T>`, which is `Sized`.
712
+ // <T as AsMaybeUninit>::MaybeUninit: Sized,
713
+ // {
714
+ // fn is_bit_valid(candidate: &MaybeValid<[T; N]>) -> bool {
715
+ // candidate.as_slice().as_slice_of_maybe_valids().iter().all(|c| T::is_bit_valid(c))
716
+ // }
717
+ // }
718
+
719
+ unsafe impl < T : TryFromBytes + Sized > TryFromBytes for [ T ]
720
+ where
721
+ // TODO: Why can't Rust infer this based on the blanket impl for `T: Sized`?
722
+ // It sets `MaybeUninit = MaybeUninit<T>`, which is `Sized`.
723
+ <T as AsMaybeUninit >:: MaybeUninit : Sized ,
724
+ {
725
+ fn is_bit_valid ( candidate : & MaybeValid < [ T ] > ) -> bool {
726
+ candidate. as_slice_of_maybe_valids ( ) . iter ( ) . all ( |c| T :: is_bit_valid ( c) )
727
+ }
728
+ }
729
+
730
+ /// # Safety
731
+ ///
732
+ /// It must be sound to transmute `&MaybeValid<$ty>` into `&$repr`.
733
+ macro_rules! unsafe_impl_try_from_bytes {
734
+ ( $ty: ty, $repr: ty, |$candidate: ident| $is_bit_valid: expr) => {
735
+ unsafe impl TryFromBytes for $ty {
736
+ fn is_bit_valid( candidate: & MaybeValid <$ty>) -> bool {
737
+ let $candidate = unsafe { & * ( candidate as * const MaybeValid <$ty> as * const $repr) } ;
738
+ $is_bit_valid
739
+ }
740
+ }
741
+ } ;
742
+ }
743
+
744
+ safety_comment ! {
745
+ /// SAFETY:
746
+ /// All of the `NonZeroXxx` types have the same layout as `Xxx`. Also, every
747
+ /// byte of such a type is required to be initialized, so it is guaranteed
748
+ /// that every byte of a `MaybeValid<NonZeroXxx>` must also be initialized.
749
+ /// Thus, it is sound to transmute a `&MaybeValid<NonZeroXxx>` to a `&Xxx`.
750
+ ///
751
+ /// TODO: Why are these impls correct (ie, ensure valid NonZeroXxx types)?
752
+ unsafe_impl_try_from_bytes!( NonZeroU8 , u8 , |n| * n != 0 ) ;
753
+ unsafe_impl_try_from_bytes!( NonZeroU16 , u16 , |n| * n != 0 ) ;
754
+ unsafe_impl_try_from_bytes!( NonZeroU32 , u32 , |n| * n != 0 ) ;
755
+ unsafe_impl_try_from_bytes!( NonZeroU64 , u64 , |n| * n != 0 ) ;
756
+ unsafe_impl_try_from_bytes!( NonZeroU128 , u128 , |n| * n != 0 ) ;
757
+ unsafe_impl_try_from_bytes!( NonZeroUsize , usize , |n| * n != 0 ) ;
758
+ unsafe_impl_try_from_bytes!( NonZeroI8 , i8 , |n| * n != 0 ) ;
759
+ unsafe_impl_try_from_bytes!( NonZeroI16 , i16 , |n| * n != 0 ) ;
760
+ unsafe_impl_try_from_bytes!( NonZeroI32 , i32 , |n| * n != 0 ) ;
761
+ unsafe_impl_try_from_bytes!( NonZeroI64 , i64 , |n| * n != 0 ) ;
762
+ unsafe_impl_try_from_bytes!( NonZeroI128 , i128 , |n| * n != 0 ) ;
763
+ unsafe_impl_try_from_bytes!( NonZeroIsize , isize , |n| * n != 0 ) ;
764
+ }
765
+
766
+ unsafe_impl_try_from_bytes ! ( bool , u8 , |byte| * byte < 2 ) ;
767
+
768
+ unsafe_impl_try_from_bytes ! ( char , [ u8 ; 4 ] , |bytes| {
769
+ let c = u32 :: from_ne_bytes( * bytes) ;
770
+ char :: from_u32( c) . is_some( )
771
+ } ) ;
772
+
773
+ unsafe_impl_try_from_bytes ! ( str , [ u8 ] , |bytes| core:: str :: from_utf8( bytes) . is_ok( ) ) ;
774
+
775
+ mod try_from_bytes_derive_example {
776
+ use super :: * ;
777
+
778
+ struct Foo {
779
+ a : u8 ,
780
+ b : u16 ,
781
+ }
782
+
783
+ impl_try_from_bytes ! ( Foo { a: u8 , b: u16 } ) ;
784
+
785
+ struct Bar ( Foo ) ;
786
+
787
+ impl Bar {
788
+ fn is_valid ( & self ) -> bool {
789
+ u16:: from ( self . 0 . a ) < self . 0 . b
790
+ }
791
+ }
792
+
793
+ impl_try_from_bytes ! ( Bar { 0 : Foo } => is_valid) ;
794
+ }
795
+
502
796
/// Types which are safe to treat as an immutable byte slice.
503
797
///
504
798
/// WARNING: Do not implement this trait yourself! Instead, use
@@ -696,29 +990,6 @@ pub unsafe trait Unaligned {
696
990
Self : Sized ;
697
991
}
698
992
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
993
/// Unsafely implements trait(s) for a type.
723
994
macro_rules! unsafe_impl {
724
995
// Implement `$trait` for `$ty` with no bounds.
0 commit comments