@@ -192,6 +192,9 @@ mod def {
192192
193193#[ allow( unreachable_pub) ] // This is a false positive on our MSRV toolchain.
194194pub use def:: Ref ;
195+ use crate :: pointer:: { BecauseRead , BecauseMutationCompatible , PtrInner , invariant:: {
196+ Aligned , BecauseExclusive , Exclusive , Initialized , Shared , Unaligned , Valid
197+ } } ;
195198
196199impl < B , T > Ref < B , T >
197200where
@@ -616,6 +619,39 @@ where
616619 // SAFETY: We don't call any methods on `b` other than those provided by
617620 // `IntoByteSlice`.
618621 let b = unsafe { r. into_byte_slice ( ) } ;
622+ let b = b. into_byte_slice ( ) ;
623+
624+ if let crate :: layout:: SizeInfo :: Sized { .. } = T :: LAYOUT . size_info {
625+ let ptr = Ptr :: from_ref ( b) ;
626+ let ptr: Ptr < ' _ , [ u8 ] , ( Shared , Unaligned , Initialized ) > = ptr. transmute :: < _ , _ , ( _ , ( _ , _ ) ) > ( ) ;
627+ // SAFETY: `T::raw_from_ptr_len` promises to preserve address and provenance in the referent.
628+ let ptr: Ptr < ' _ , T , ( Shared , Unaligned , Initialized ) > = unsafe {
629+ ptr. cast_unsized ( |ptr| {
630+ let ptr = T :: raw_from_ptr_len (
631+ ptr. as_non_null ( ) . cast ( ) ,
632+ <T :: PointerMetadata as crate :: PointerMetadata >:: from_elem_count ( 0 ) ,
633+ ) ;
634+ // SAFETY: The safety invariants of `Ptr::new` (see definition) are
635+ // satisfied:
636+ // 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
637+ // provenance for its referent, because it derived from `self`
638+ // using a series of provenance-preserving operations, and
639+ // because `self` has valid provenance for its referent. By the
640+ // same argument, `ptr`'s referent is entirely contained within
641+ // the same allocated object as `self`'s referent.
642+ // 1. If `ptr`'s referent is not zero sized, then the allocation of
643+ // `ptr` is guaranteed to live for at least `'a`, because `ptr`
644+ // is entirely contained in `self`, which lives for at least `'a`
645+ // by invariant on `Ptr`.
646+ unsafe { PtrInner :: new ( ptr) }
647+ } )
648+ } ;
649+
650+ // SAFETY: By invariant on `r`, we know that alignment is valid.
651+ let ptr = unsafe { ptr. assume_alignment :: < Aligned > ( ) } ;
652+ let ptr = ptr. recall_validity :: < Valid , _ > ( ) ;
653+ return ptr. as_ref ( ) ;
654+ }
619655
620656 // PANICS: By post-condition on `into_byte_slice`, `b`'s size and
621657 // alignment are valid for `T`. By post-condition, `b.into_byte_slice()`
@@ -650,6 +686,58 @@ where
650686 // SAFETY: We don't call any methods on `b` other than those provided by
651687 // `IntoByteSliceMut`.
652688 let b = unsafe { r. into_byte_slice_mut ( ) } ;
689+ let b = b. into_byte_slice_mut ( ) ;
690+
691+ if let crate :: layout:: SizeInfo :: Sized { .. } = T :: LAYOUT . size_info {
692+ let ptr = Ptr :: from_mut ( b) ;
693+ let ptr: Ptr < ' _ , [ u8 ] , ( Exclusive , Unaligned , Initialized ) > = ptr. transmute :: <
694+ [ u8 ] ,
695+ Initialized ,
696+ (
697+ BecauseMutationCompatible ,
698+ (
699+ BecauseRead ,
700+ ( BecauseExclusive , BecauseExclusive ) ,
701+ ) ,
702+ ) ,
703+ > ( ) ;
704+ // SAFETY: `T::raw_from_ptr_len` promises to preserve address and provenance in the referent.
705+ let ptr: Ptr < ' _ , T , ( Exclusive , Unaligned , Initialized ) > = unsafe {
706+ ptr. cast_unsized :: < _ , _ , ( BecauseRead , ( BecauseExclusive , BecauseExclusive ) ) > ( |ptr| {
707+ let ptr = T :: raw_from_ptr_len (
708+ ptr. as_non_null ( ) . cast ( ) ,
709+ <T :: PointerMetadata as crate :: PointerMetadata >:: from_elem_count ( 0 ) ,
710+ ) ;
711+ // SAFETY: The safety invariants of `Ptr::new` (see definition) are
712+ // satisfied:
713+ // 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
714+ // provenance for its referent, because it derived from `self`
715+ // using a series of provenance-preserving operations, and
716+ // because `self` has valid provenance for its referent. By the
717+ // same argument, `ptr`'s referent is entirely contained within
718+ // the same allocated object as `self`'s referent.
719+ // 1. If `ptr`'s referent is not zero sized, then the allocation of
720+ // `ptr` is guaranteed to live for at least `'a`, because `ptr`
721+ // is entirely contained in `self`, which lives for at least `'a`
722+ // by invariant on `Ptr`.
723+ unsafe { PtrInner :: new ( ptr) }
724+ } )
725+ } ;
726+
727+ // SAFETY: By invariant on `r`, we know that alignment is valid.
728+ let ptr = unsafe { ptr. assume_alignment :: < Aligned > ( ) } ;
729+ let ptr = ptr. recall_validity :: <
730+ Valid ,
731+ (
732+ BecauseMutationCompatible ,
733+ (
734+ BecauseRead ,
735+ ( BecauseExclusive , BecauseExclusive ) ,
736+ ) ,
737+ ) ,
738+ > ( ) ;
739+ return ptr. as_mut ( ) ;
740+ }
653741
654742 // PANICS: By post-condition on `into_byte_slice_mut`, `b`'s size and
655743 // alignment are valid for `T`. By post-condition,
@@ -763,11 +851,44 @@ where
763851 // SAFETY: We don't call any methods on `b` other than those provided by
764852 // `ByteSlice`.
765853 let b = unsafe { self . as_byte_slice ( ) } ;
854+ let b = b. deref ( ) ;
855+
856+ if let crate :: layout:: SizeInfo :: Sized { .. } = T :: LAYOUT . size_info {
857+ let ptr = Ptr :: from_ref ( b) ;
858+ let ptr: Ptr < ' _ , [ u8 ] , ( Shared , Unaligned , Initialized ) > = ptr. transmute :: < _ , _ , ( _ , ( _ , _ ) ) > ( ) ;
859+ // SAFETY: `T::raw_from_ptr_len` promises to preserve address and provenance in the referent.
860+ let ptr: Ptr < ' _ , T , ( Shared , Unaligned , Initialized ) > = unsafe {
861+ ptr. cast_unsized ( |ptr| {
862+ let ptr = T :: raw_from_ptr_len (
863+ ptr. as_non_null ( ) . cast ( ) ,
864+ <T :: PointerMetadata as crate :: PointerMetadata >:: from_elem_count ( 0 ) ,
865+ ) ;
866+ // SAFETY: The safety invariants of `Ptr::new` (see definition) are
867+ // satisfied:
868+ // 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
869+ // provenance for its referent, because it derived from `self`
870+ // using a series of provenance-preserving operations, and
871+ // because `self` has valid provenance for its referent. By the
872+ // same argument, `ptr`'s referent is entirely contained within
873+ // the same allocated object as `self`'s referent.
874+ // 1. If `ptr`'s referent is not zero sized, then the allocation of
875+ // `ptr` is guaranteed to live for at least `'a`, because `ptr`
876+ // is entirely contained in `self`, which lives for at least `'a`
877+ // by invariant on `Ptr`.
878+ unsafe { PtrInner :: new ( ptr) }
879+ } )
880+ } ;
881+
882+ // SAFETY: By invariant on `r`, we know that alignment is valid.
883+ let ptr = unsafe { ptr. assume_alignment :: < Aligned > ( ) } ;
884+ let ptr = ptr. recall_validity :: < Valid , _ > ( ) ;
885+ return ptr. as_ref ( ) ;
886+ }
766887
767888 // PANICS: By postcondition on `as_byte_slice`, `b`'s size and alignment
768889 // are valid for `T`, and by invariant on `ByteSlice`, these are
769890 // preserved through `.deref()`, so this `unwrap` will not panic.
770- let ptr = Ptr :: from_ref ( b. deref ( ) )
891+ let ptr = Ptr :: from_ref ( b)
771892 . try_cast_into_no_leftover :: < T , BecauseImmutable > ( None )
772893 . expect ( "zerocopy internal error: Deref::deref should be infallible" ) ;
773894 let ptr = ptr. recall_validity ( ) ;
@@ -791,12 +912,64 @@ where
791912 // SAFETY: We don't call any methods on `b` other than those provided by
792913 // `ByteSliceMut`.
793914 let b = unsafe { self . as_byte_slice_mut ( ) } ;
915+ let b = b. deref_mut ( ) ;
916+
917+ if let crate :: layout:: SizeInfo :: Sized { .. } = T :: LAYOUT . size_info {
918+ let ptr = Ptr :: from_mut ( b) ;
919+ let ptr: Ptr < ' _ , [ u8 ] , ( Exclusive , Unaligned , Initialized ) > = ptr. transmute :: <
920+ [ u8 ] ,
921+ Initialized ,
922+ (
923+ BecauseMutationCompatible ,
924+ (
925+ BecauseRead ,
926+ ( BecauseExclusive , BecauseExclusive ) ,
927+ ) ,
928+ ) ,
929+ > ( ) ;
930+ // SAFETY: `T::raw_from_ptr_len` promises to preserve address and provenance in the referent.
931+ let ptr: Ptr < ' _ , T , ( Exclusive , Unaligned , Initialized ) > = unsafe {
932+ ptr. cast_unsized :: < _ , _ , ( BecauseRead , ( BecauseExclusive , BecauseExclusive ) ) > ( |ptr| {
933+ let ptr = T :: raw_from_ptr_len (
934+ ptr. as_non_null ( ) . cast ( ) ,
935+ <T :: PointerMetadata as crate :: PointerMetadata >:: from_elem_count ( 0 ) ,
936+ ) ;
937+ // SAFETY: The safety invariants of `Ptr::new` (see definition) are
938+ // satisfied:
939+ // 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
940+ // provenance for its referent, because it derived from `self`
941+ // using a series of provenance-preserving operations, and
942+ // because `self` has valid provenance for its referent. By the
943+ // same argument, `ptr`'s referent is entirely contained within
944+ // the same allocated object as `self`'s referent.
945+ // 1. If `ptr`'s referent is not zero sized, then the allocation of
946+ // `ptr` is guaranteed to live for at least `'a`, because `ptr`
947+ // is entirely contained in `self`, which lives for at least `'a`
948+ // by invariant on `Ptr`.
949+ unsafe { PtrInner :: new ( ptr) }
950+ } )
951+ } ;
952+
953+ // SAFETY: By invariant on `r`, we know that alignment is valid.
954+ let ptr = unsafe { ptr. assume_alignment :: < Aligned > ( ) } ;
955+ let ptr = ptr. recall_validity :: <
956+ Valid ,
957+ (
958+ BecauseMutationCompatible ,
959+ (
960+ BecauseRead ,
961+ ( BecauseExclusive , BecauseExclusive ) ,
962+ ) ,
963+ ) ,
964+ > ( ) ;
965+ return ptr. as_mut ( ) ;
966+ }
794967
795968 // PANICS: By postcondition on `as_byte_slice_mut`, `b`'s size and
796969 // alignment are valid for `T`, and by invariant on `ByteSlice`, these
797970 // are preserved through `.deref_mut()`, so this `unwrap` will not
798971 // panic.
799- let ptr = Ptr :: from_mut ( b. deref_mut ( ) )
972+ let ptr = Ptr :: from_mut ( b)
800973 . try_cast_into_no_leftover :: < T , BecauseExclusive > ( None )
801974 . expect ( "zerocopy internal error: DerefMut::deref_mut should be infallible" ) ;
802975 let ptr = ptr. recall_validity :: < _ , ( _ , ( _ , ( BecauseExclusive , BecauseExclusive ) ) ) > ( ) ;
@@ -879,6 +1052,61 @@ mod tests {
8791052
8801053 use super :: * ;
8811054 use crate :: util:: testutil:: * ;
1055+ use test:: { self , Bencher } ;
1056+
1057+ #[ bench]
1058+ fn bench_from_bytes_sized ( b : & mut Bencher ) {
1059+ let buf = Align :: < [ u8 ; 8 ] , AU64 > :: default ( ) ;
1060+ // `buf.t` should be aligned to 8, so this should always succeed.
1061+ let bytes = & buf. t [ ..] ;
1062+ b. iter ( || test:: black_box ( Ref :: < _ , AU64 > :: from_bytes ( test:: black_box ( bytes) ) . unwrap ( ) ) ) ;
1063+ }
1064+
1065+ #[ bench]
1066+ fn bench_into_ref_sized ( b : & mut Bencher ) {
1067+ let buf = Align :: < [ u8 ; 8 ] , AU64 > :: default ( ) ;
1068+ let bytes = & buf. t [ ..] ;
1069+ let r = Ref :: < _ , AU64 > :: from_bytes ( bytes) . unwrap ( ) ;
1070+ b. iter ( || {
1071+ test:: black_box ( Ref :: into_ref ( test:: black_box ( r) ) )
1072+ } ) ;
1073+ }
1074+
1075+ #[ bench]
1076+ fn bench_into_mut_sized ( b : & mut Bencher ) {
1077+ let mut buf = Align :: < [ u8 ; 8 ] , AU64 > :: default ( ) ;
1078+ let _ = Ref :: < _ , AU64 > :: from_bytes ( & mut buf. t [ ..] ) . unwrap ( ) ;
1079+ b. iter ( move || {
1080+ // SAFETY: The preceding `from_bytes` succeeded, and so we know that
1081+ // `&mut buf.t[.]
1082+ let r = unsafe { Ref :: < & mut [ u8 ] , AU64 > :: new_unchecked ( & mut buf. t [ ..] ) } ;
1083+ test:: black_box ( Ref :: into_mut ( test:: black_box ( r) ) ) ;
1084+ } ) ;
1085+ }
1086+
1087+ #[ bench]
1088+ fn bench_deref_sized ( b : & mut Bencher ) {
1089+ let buf = Align :: < [ u8 ; 8 ] , AU64 > :: default ( ) ;
1090+ let bytes = & buf. t [ ..] ;
1091+ let r = Ref :: < _ , AU64 > :: from_bytes ( bytes) . unwrap ( ) ;
1092+ b. iter ( || {
1093+ let temp = test:: black_box ( r) ;
1094+ test:: black_box ( temp. deref ( ) ) ;
1095+ } ) ;
1096+ }
1097+
1098+ #[ bench]
1099+ fn bench_deref_mut_sized ( b : & mut Bencher ) {
1100+ let mut buf = Align :: < [ u8 ; 8 ] , AU64 > :: default ( ) ;
1101+ let _ = Ref :: < _ , AU64 > :: from_bytes ( & mut buf. t [ ..] ) . unwrap ( ) ;
1102+ b. iter ( || {
1103+ // SAFETY: The preceding `from_bytes` succeeded, and so we know that
1104+ // `&mut buf.t[.]
1105+ let r = unsafe { Ref :: < & mut [ u8 ] , AU64 > :: new_unchecked ( & mut buf. t [ ..] ) } ;
1106+ let mut temp = test:: black_box ( r) ;
1107+ test:: black_box ( temp. deref_mut ( ) ) ;
1108+ } ) ;
1109+ }
8821110
8831111 #[ test]
8841112 fn test_mut_slice_into_ref ( ) {
0 commit comments