@@ -60,7 +60,45 @@ pub mod cast {
6060 ///
6161 /// The returned pointer refers to a non-strict subset of the bytes of
6262 /// `src`'s referent, and has the same provenance as `src`.
63- fn project ( src : PtrInner < ' _ , Src > ) -> * mut Dst ;
63+ #[ must_use]
64+ fn project_inner ( src : PtrInner < ' _ , Src > ) -> * mut Dst ;
65+
66+ /// Projects a [`PtrInner`] from `Src` to `Dst`.
67+ ///
68+ /// # Safety
69+ ///
70+ /// The caller may assume that the resulting `PtrInner` addresses a
71+ /// subset of the bytes of `src`'s referent.
72+ #[ must_use]
73+ #[ inline( always) ]
74+ fn project ( src : PtrInner < ' _ , Src > ) -> PtrInner < ' _ , Dst > {
75+ let projected_raw = Self :: project_inner ( src) ;
76+
77+ // SAFETY: `src`'s referent lives at a `NonNull` address, and is
78+ // either zero-sized or lives in an allocation. In either case, it
79+ // does not wrap around the address space [1], and so none of the
80+ // addresses contained in it or one-past-the-end of it are null.
81+ //
82+ // By invariant on `Self: Project`, `Self::project` is a
83+ // provenance-preserving projection which preserves or shrinks the
84+ // set of referent bytes, so `projected_raw` references a subset of
85+ // `src`'s referent, and so it cannot be null.
86+ //
87+ // [1] https://doc.rust-lang.org/1.92.0/std/ptr/index.html#allocation
88+ let projected_non_null = unsafe { core:: ptr:: NonNull :: new_unchecked ( projected_raw) } ;
89+
90+ // SAFETY: As described in the preceding safety comment, `projected_raw`,
91+ // and thus `projected_non_null`, addresses a subset of `src`'s
92+ // referent. Thus, `projected_non_null` either:
93+ // - Addresses zero bytes or,
94+ // - Addresses a subset of the referent of `src`. In this case, `src`
95+ // has provenance for its referent, which lives in an allocation.
96+ // Since `projected_non_null` was constructed using a sequence of
97+ // provenance-preserving operations, it also has provenance for its
98+ // referent and that referent lives in an allocation. By invariant on
99+ // `src`, that allocation lives for `'a`.
100+ unsafe { PtrInner :: new ( projected_non_null) }
101+ }
64102 }
65103
66104 /// A [`Project`] which preserves the address of the referent – a pointer
@@ -72,6 +110,13 @@ pub mod cast {
72110 /// shrink the set of referent bytes, and it may change the referent's type.
73111 pub unsafe trait Cast < Src : ?Sized , Dst : ?Sized > : Project < Src , Dst > { }
74112
113+ /// A [`Cast`] which does not shrink the set of referent bytes.
114+ ///
115+ /// # Safety
116+ ///
117+ /// A `CastExact` projection must preserve the set of referent bytes.
118+ pub unsafe trait CastExact < Src : ?Sized , Dst : ?Sized > : Cast < Src , Dst > { }
119+
75120 /// A no-op pointer cast.
76121 #[ derive( Default , Copy , Clone ) ]
77122 #[ allow( missing_debug_implementations) ]
@@ -82,14 +127,17 @@ pub mod cast {
82127 // bytes.
83128 unsafe impl < T : ?Sized > Project < T , T > for IdCast {
84129 #[ inline( always) ]
85- fn project ( src : PtrInner < ' _ , T > ) -> * mut T {
130+ fn project_inner ( src : PtrInner < ' _ , T > ) -> * mut T {
86131 src. as_ptr ( )
87132 }
88133 }
89134
90135 // SAFETY: The `Project::project` impl preserves referent address.
91136 unsafe impl < T : ?Sized > Cast < T , T > for IdCast { }
92137
138+ // SAFETY: The `Project::project` impl preserves referent size.
139+ unsafe impl < T : ?Sized > CastExact < T , T > for IdCast { }
140+
93141 /// A pointer cast which preserves or shrinks the set of referent bytes of
94142 /// a statically-sized referent.
95143 ///
@@ -107,7 +155,7 @@ pub mod cast {
107155 // operations preserve provenance.
108156 unsafe impl < Src , Dst > Project < Src , Dst > for CastSized {
109157 #[ inline( always) ]
110- fn project ( src : PtrInner < ' _ , Src > ) -> * mut Dst {
158+ fn project_inner ( src : PtrInner < ' _ , Src > ) -> * mut Dst {
111159 static_assert ! ( Src , Dst => mem:: size_of:: <Src >( ) >= mem:: size_of:: <Dst >( ) ) ;
112160 src. as_ptr ( ) . cast :: < Dst > ( )
113161 }
@@ -116,6 +164,37 @@ pub mod cast {
116164 // SAFETY: The `Project::project` impl preserves referent address.
117165 unsafe impl < Src , Dst > Cast < Src , Dst > for CastSized { }
118166
167+ /// A pointer cast which preserves the set of referent bytes of a
168+ /// statically-sized referent.
169+ ///
170+ /// # Safety
171+ ///
172+ /// The implementation of [`Project`] uses a compile-time assertion to
173+ /// guarantee that `Dst` has the same size as `Src`. Thus, `CastSizedExact`
174+ /// has a sound implementation of [`Project`] for all `Src` and `Dst` – the
175+ /// caller may pass any `Src` and `Dst` without being responsible for
176+ /// soundness.
177+ #[ allow( missing_debug_implementations, missing_copy_implementations) ]
178+ pub enum CastSizedExact { }
179+
180+ // SAFETY: By the `static_assert!`, `Dst` has the same size as `Src`,
181+ // and so all casts preserve the set of referent bytes. All operations
182+ // preserve provenance.
183+ unsafe impl < Src , Dst > Project < Src , Dst > for CastSizedExact {
184+ #[ inline( always) ]
185+ fn project_inner ( src : PtrInner < ' _ , Src > ) -> * mut Dst {
186+ static_assert ! ( Src , Dst => mem:: size_of:: <Src >( ) == mem:: size_of:: <Dst >( ) ) ;
187+ src. as_ptr ( ) . cast :: < Dst > ( )
188+ }
189+ }
190+
191+ // SAFETY: The `Project::project` impl preserves referent address.
192+ unsafe impl < Src , Dst > Cast < Src , Dst > for CastSizedExact { }
193+
194+ // SAFETY: By the `static_assert!`, `Project::project` impl preserves
195+ // referent size.
196+ unsafe impl < Src , Dst > CastExact < Src , Dst > for CastSizedExact { }
197+
119198 /// A pointer cast which preserves or shrinks the set of referent bytes of
120199 /// a dynamically-sized referent.
121200 ///
@@ -129,30 +208,34 @@ pub mod cast {
129208 #[ allow( missing_debug_implementations, missing_copy_implementations) ]
130209 pub enum CastUnsized { }
131210
132- // SAFETY: The `static_assert!` ensures that `Src` and `Dst` have the same
133- // `SizeInfo`. Thus, casting preserves the set of referent bytes. All
134- // operations are provenance-preserving.
211+ // SAFETY: By the `static_assert!`, `Src` and `Dst` are either:
212+ // - Both sized and equal in size
213+ // - Both slice DSTs with the same alignment, trailing slice offset, and
214+ // element size. These ensure that any given pointer metadata encodes the
215+ // same size for both `Src` and `Dst` (note that the alignment is required
216+ // as it affects the amount of trailing padding).
135217 unsafe impl < Src , Dst > Project < Src , Dst > for CastUnsized
136218 where
137219 Src : ?Sized + KnownLayout ,
138220 Dst : ?Sized + KnownLayout < PointerMetadata = Src :: PointerMetadata > ,
139221 {
140222 #[ inline( always) ]
141- fn project ( src : PtrInner < ' _ , Src > ) -> * mut Dst {
223+ fn project_inner ( src : PtrInner < ' _ , Src > ) -> * mut Dst {
142224 // FIXME:
143225 // - Is the alignment check necessary for soundness? It's not
144226 // necessary for the soundness of the `Project` impl, but what
145227 // about the soundness of particular use sites?
146- // - Do we want this to support shrinking casts as well?
228+ // - Do we want this to support shrinking casts as well? If so,
229+ // we'll need to remove the `CastExact` impl.
147230 static_assert ! ( Src : ?Sized + KnownLayout , Dst : ?Sized + KnownLayout => {
148231 let t = <Src as KnownLayout >:: LAYOUT ;
149232 let u = <Dst as KnownLayout >:: LAYOUT ;
150- t . align . get ( ) >= u . align . get ( ) && match ( t. size_info, u. size_info) {
233+ match ( t. size_info, u. size_info) {
151234 ( SizeInfo :: Sized { size: t } , SizeInfo :: Sized { size: u } ) => t == u,
152235 (
153236 SizeInfo :: SliceDst ( TrailingSliceLayout { offset: t_offset, elem_size: t_elem_size } ) ,
154237 SizeInfo :: SliceDst ( TrailingSliceLayout { offset: u_offset, elem_size: u_elem_size } )
155- ) => t_offset == u_offset && t_elem_size == u_elem_size,
238+ ) => t . align . get ( ) >= u . align . get ( ) && t_offset == u_offset && t_elem_size == u_elem_size,
156239 _ => false ,
157240 }
158241 } ) ;
@@ -170,6 +253,20 @@ pub mod cast {
170253 {
171254 }
172255
256+ // SAFETY: By the `static_assert!` in `Project::project`, `Src` and `Dst`
257+ // are either:
258+ // - Both sized and equal in size
259+ // - Both slice DSTs with the same alignment, trailing slice offset, and
260+ // element size. These ensure that any given pointer metadata encodes the
261+ // same size for both `Src` and `Dst` (note that the alignment is required
262+ // as it affects the amount of trailing padding).
263+ unsafe impl < Src , Dst > CastExact < Src , Dst > for CastUnsized
264+ where
265+ Src : ?Sized + KnownLayout ,
266+ Dst : ?Sized + KnownLayout < PointerMetadata = Src :: PointerMetadata > ,
267+ {
268+ }
269+
173270 /// A field projection
174271 ///
175272 /// A `Projection` is a [`Project`] which implements projection by
@@ -188,7 +285,7 @@ pub mod cast {
188285 T : HasField < F , VARIANT_ID , FIELD_ID > ,
189286 {
190287 #[ inline( always) ]
191- fn project ( src : PtrInner < ' _ , T > ) -> * mut T :: Type {
288+ fn project_inner ( src : PtrInner < ' _ , T > ) -> * mut T :: Type {
192289 T :: project ( src)
193290 }
194291 }
@@ -221,7 +318,7 @@ pub mod cast {
221318 UV : Project < U , V > ,
222319 {
223320 #[ inline( always) ]
224- fn project ( t : PtrInner < ' _ , T > ) -> * mut V {
321+ fn project_inner ( t : PtrInner < ' _ , T > ) -> * mut V {
225322 t. project :: < _ , TU > ( ) . project :: < _ , UV > ( ) . as_ptr ( )
226323 }
227324 }
@@ -239,6 +336,19 @@ pub mod cast {
239336 {
240337 }
241338
339+ // SAFETY: Since the `Project::project` impl delegates to `TU::project` and
340+ // `UV::project`, and since `TU` and `UV` are `CastExact`, the `Project::project`
341+ // impl preserves the set of referent bytes.
342+ unsafe impl < T , U , V , TU , UV > CastExact < T , V > for TransitiveProject < U , TU , UV >
343+ where
344+ T : ?Sized ,
345+ U : ?Sized ,
346+ V : ?Sized ,
347+ TU : CastExact < T , U > ,
348+ UV : CastExact < U , V > ,
349+ {
350+ }
351+
242352 /// A cast from `T` to `[u8]`.
243353 pub ( crate ) struct AsBytesCast ;
244354
@@ -251,7 +361,7 @@ pub mod cast {
251361 // true of other proofs in this codebase). Is this guaranteed anywhere?
252362 unsafe impl < T : ?Sized + KnownLayout > Project < T , [ u8 ] > for AsBytesCast {
253363 #[ inline( always) ]
254- fn project ( src : PtrInner < ' _ , T > ) -> * mut [ u8 ] {
364+ fn project_inner ( src : PtrInner < ' _ , T > ) -> * mut [ u8 ] {
255365 let bytes = match T :: size_of_val_raw ( src. as_non_null ( ) ) {
256366 Some ( bytes) => bytes,
257367 // SAFETY: `KnownLayout::size_of_val_raw` promises to always
@@ -268,4 +378,7 @@ pub mod cast {
268378
269379 // SAFETY: The `Project::project` impl preserves referent address.
270380 unsafe impl < T : ?Sized + KnownLayout > Cast < T , [ u8 ] > for AsBytesCast { }
381+
382+ // SAFETY: The `Project::project` impl preserves the set of referent bytes.
383+ unsafe impl < T : ?Sized + KnownLayout > CastExact < T , [ u8 ] > for AsBytesCast { }
271384}
0 commit comments