@@ -171,7 +171,10 @@ mod _external {
171171/// Methods for converting to and from `Ptr` and Rust's safe reference types.
172172mod _conversions {
173173 use super :: * ;
174- use crate :: util:: { AlignmentVariance , Covariant , TransparentWrapper , ValidityVariance } ;
174+ use crate :: {
175+ pointer:: transmute:: { CastFrom , TransmuteFromAlignment , TransmuteFromPtr } ,
176+ util:: { AlignmentVariance , Covariant , TransparentWrapper , ValidityVariance } ,
177+ } ;
175178
176179 /// `&'a T` → `Ptr<'a, T>`
177180 impl < ' a , T : ?Sized > Ptr < ' a , Valid < T > , ( Shared , Aligned ) > {
@@ -337,6 +340,54 @@ mod _conversions {
337340 }
338341 }
339342
343+ /// `Ptr<'a, T>` → `Ptr<'a, U>`
344+ impl < ' a , V , I > Ptr < ' a , V , I >
345+ where
346+ V : Validity ,
347+ I : Invariants ,
348+ {
349+ /// # Safety
350+ /// - TODO: `UnsafeCell` agreement
351+ /// - The caller promises that the returned `Ptr` satisfies alignment
352+ /// `A`
353+ /// - The caller promises that the returned `Ptr` satisfies validity `V`
354+ pub ( crate ) unsafe fn transmute_unchecked < U , A > ( self ) -> Ptr < ' a , U , ( I :: Aliasing , A ) >
355+ where
356+ A : Alignment ,
357+ U : Validity ,
358+ U :: Inner : CastFrom < V :: Inner > ,
359+ {
360+ // SAFETY:
361+ // - By invariant on `CastFrom::cast_from`:
362+ // - This cast preserves address and referent size, and thus the
363+ // returned pointer addresses the same bytes as `p`
364+ // - This cast preserves provenance
365+ // - TODO: `UnsafeCell` agreement
366+ let ptr =
367+ unsafe { self . cast_unsized_unchecked :: < U :: Inner , _ > ( |p| U :: Inner :: cast_from ( p) ) } ;
368+ // SAFETY: The caller promises that alignment is satisfied.
369+ let ptr = unsafe { ptr. assume_alignment ( ) } ;
370+ // SAFETY: The caller promises that validity is satisfied.
371+ let ptr = unsafe { ptr. assume_validity :: < U > ( ) } ;
372+ ptr. unify_validity ( )
373+ }
374+
375+ pub ( crate ) fn transmute < U , A , RT , RA > ( self ) -> Ptr < ' a , U , ( I :: Aliasing , A ) >
376+ where
377+ A : Alignment ,
378+ U : TransmuteFromPtr < V , I :: Aliasing , RT > ,
379+ U :: Inner : TransmuteFromAlignment < U :: Inner , I :: Alignment , A , RA > + CastFrom < V :: Inner > ,
380+ {
381+ // SAFETY:
382+ // - TODO: `UnsafeCell` agreement
383+ // - By invariant on `TransmuteFromPtr`, it is sound to treat the
384+ // resulting pointer as having alignment `A`
385+ // - By invariant on `TransmuteFromPtr`, it is sound to treat the
386+ // resulting pointer as having validity `V`
387+ unsafe { self . transmute_unchecked ( ) }
388+ }
389+ }
390+
340391 /// `Ptr<'a, T = Wrapper<U>>` → `Ptr<'a, U>`
341392 impl < ' a , V , I > Ptr < ' a , V , I >
342393 where
@@ -428,7 +479,10 @@ mod _conversions {
428479/// State transitions between invariants.
429480mod _transitions {
430481 use super :: * ;
431- use crate :: { AlignmentError , TryFromBytes , ValidityError } ;
482+ use crate :: {
483+ pointer:: transmute:: { CastFrom , TransmuteFromPtr , TryTransmuteFromPtr } ,
484+ AlignmentError , TryFromBytes , ValidityError ,
485+ } ;
432486
433487 impl < ' a , V , I > Ptr < ' a , V , I >
434488 where
@@ -649,6 +703,22 @@ mod _transitions {
649703 }
650704 }
651705
706+ impl < ' a , V , I > Ptr < ' a , V , I >
707+ where
708+ V : Validity ,
709+ I : Invariants ,
710+ I :: Aliasing : Reference ,
711+ {
712+ /// Forgets that `self` is an `Exclusive` pointer, downgrading it to a
713+ /// `Shared` pointer.
714+ #[ doc( hidden) ]
715+ #[ must_use]
716+ #[ inline]
717+ pub const fn forget_exclusive ( self ) -> Ptr < ' a , V , I :: WithAliasing < Shared > > {
718+ unsafe { self . assume_invariants ( ) }
719+ }
720+ }
721+
652722 impl < ' a , T , I > Ptr < ' a , Initialized < T > , I >
653723 where
654724 T : ?Sized ,
@@ -660,14 +730,12 @@ mod _transitions {
660730 #[ inline]
661731 // TODO(#859): Reconsider the name of this method before making it
662732 // public.
663- pub const fn bikeshed_recall_valid ( self ) -> Ptr < ' a , Valid < T > , I >
733+ pub fn bikeshed_recall_valid < R > ( self ) -> Ptr < ' a , Valid < T > , I >
664734 where
665- T : crate :: FromBytes ,
735+ Valid < T > : TransmuteFromPtr < Initialized < T > , I :: Aliasing , R > ,
736+ <Valid < T > as Validity >:: Inner : CastFrom < T > ,
666737 {
667- // SAFETY: The bound `T: FromBytes` ensures that any initialized
668- // sequence of bytes is bit-valid for `T`. `V = Initialized<T>`
669- // ensures that all of the referent bytes are initialized.
670- unsafe { self . assume_valid ( ) }
738+ self . transmute ( ) . unify_invariants ( )
671739 }
672740
673741 /// Checks that `self`'s referent is validly initialized for `T`,
@@ -687,7 +755,12 @@ mod _transitions {
687755 mut self ,
688756 ) -> Result < Ptr < ' a , Valid < T > , I > , ValidityError < Self , T > >
689757 where
690- T : TryFromBytes + Read < I :: Aliasing , R > ,
758+ T : TryFromBytes , // + Read<I::Aliasing, R>,
759+ Valid < T > : TryTransmuteFromPtr < Initialized < T > , I :: Aliasing , R > ,
760+ // NOTE: This bound ought to be implied, but leaving it out causes
761+ // Rust to infinite loop during trait solving.
762+ <Valid < T > as Validity >:: Inner :
763+ crate :: pointer:: transmute:: CastFrom < <Initialized < T > as Validity >:: Inner > ,
691764 I :: Aliasing : Reference ,
692765 {
693766 // This call may panic. If that happens, it doesn't cause any soundness
@@ -702,12 +775,63 @@ mod _transitions {
702775 }
703776 }
704777 }
778+
779+ impl < ' a , V , I > Ptr < ' a , V , I >
780+ where
781+ V : Validity ,
782+ I : Invariants ,
783+ {
784+ /// Attempts to transmute a `Ptr<T>` into a `Ptr<U>`.
785+ ///
786+ /// # Panics
787+ ///
788+ /// This method will panic if
789+ /// [`U::is_bit_valid`][TryFromBytes::is_bit_valid] panics.
790+ ///
791+ /// # Safety
792+ ///
793+ /// On success, the returned `Ptr` addresses the same bytes as `self`.
794+ ///
795+ /// On error, unsafe code may rely on this method's returned
796+ /// `ValidityError` containing `self`.
797+ #[ inline]
798+ pub ( crate ) fn try_transmute < U , R , RR > (
799+ mut self ,
800+ ) -> Result < Ptr < ' a , U , I :: WithAlignment < Unknown > > , ValidityError < Self , U :: Inner > >
801+ where
802+ U : Validity + TryTransmuteFromPtr < V , I :: Aliasing , R > ,
803+ U :: Inner : TryFromBytes + CastFrom < V :: Inner > ,
804+ Initialized < U :: Inner > : TransmuteFromPtr < V , I :: Aliasing , RR > ,
805+ // TODO: The `Sized` bound here is only required in order to call
806+ // `.bikeshed_try_into_aligned`. There are other ways of getting the
807+ // alignment of a type, and we could use these if we need to drop
808+ // this bound.
809+ <Initialized < U :: Inner > as Validity >:: Inner : Sized + CastFrom < V :: Inner > ,
810+ I :: Aliasing : Reference ,
811+ {
812+ let is_bit_valid = {
813+ let ptr = self . reborrow ( ) ;
814+ let ptr = ptr. transmute :: < Initialized < U :: Inner > , Unknown , _ , _ > ( ) ;
815+ // This call may panic. If that happens, it doesn't cause any
816+ // soundness issues, as we have not generated any invalid state
817+ // which we need to fix before returning.
818+ <U :: Inner as TryFromBytes >:: is_bit_valid ( ptr)
819+ } ;
820+
821+ if is_bit_valid {
822+ let ptr = unsafe { self . transmute_unchecked ( ) } ;
823+ Ok ( ptr. unify_invariants ( ) )
824+ } else {
825+ Err ( ValidityError :: new ( self ) )
826+ }
827+ }
828+ }
705829}
706830
707831/// Casts of the referent type.
708832mod _casts {
709833 use super :: * ;
710- use crate :: { CastError , SizeError } ;
834+ use crate :: { pointer :: transmute :: BecauseRead , CastError , SizeError } ;
711835
712836 impl < ' a , V , I > Ptr < ' a , V , I >
713837 where
@@ -866,7 +990,7 @@ mod _casts {
866990 } )
867991 } ;
868992
869- ptr. bikeshed_recall_aligned ( ) . bikeshed_recall_valid ( )
993+ ptr. bikeshed_recall_aligned ( ) . bikeshed_recall_valid :: < ( BecauseRead , _ ) > ( )
870994 }
871995 }
872996
@@ -1125,6 +1249,7 @@ mod tests {
11251249
11261250 mod test_ptr_try_cast_into_soundness {
11271251 use super :: * ;
1252+ use crate :: IntoBytes ;
11281253
11291254 // This test is designed so that if `Ptr::try_cast_into_xxx` are
11301255 // buggy, it will manifest as unsoundness that Miri can detect.
@@ -1164,7 +1289,9 @@ mod tests {
11641289 } ;
11651290
11661291 // SAFETY: The bytes in `slf` must be initialized.
1167- unsafe fn validate_and_get_len < T : ?Sized + KnownLayout + FromBytes > (
1292+ unsafe fn validate_and_get_len <
1293+ T : ?Sized + KnownLayout + FromBytes + Immutable ,
1294+ > (
11681295 slf : Ptr < ' _ , Initialized < T > , ( Shared , Aligned ) > ,
11691296 ) -> usize {
11701297 let t = slf. bikeshed_recall_valid ( ) . as_ref ( ) ;
0 commit comments