@@ -78,6 +78,13 @@ pub mod cast {
7878 /// shrink the set of referent bytes, and it may change the referent's type.
7979 pub unsafe trait Cast < Src : ?Sized , Dst : ?Sized > : Project < Src , Dst > { }
8080
81+ /// A [`Cast`] which does not shrink the set of referent bytes.
82+ ///
83+ /// # Safety
84+ ///
85+ /// A `CastExact` projection must preserve the set of referent bytes.
86+ pub unsafe trait CastExact < Src : ?Sized , Dst : ?Sized > : Cast < Src , Dst > { }
87+
8188 /// A no-op pointer cast.
8289 #[ derive( Default , Copy , Clone ) ]
8390 #[ allow( missing_debug_implementations) ]
@@ -96,6 +103,9 @@ pub mod cast {
96103 // SAFETY: The `Project::project` impl preserves referent address.
97104 unsafe impl < T : ?Sized > Cast < T , T > for IdCast { }
98105
106+ // SAFETY: The `Project::project` impl preserves referent size.
107+ unsafe impl < T : ?Sized > CastExact < T , T > for IdCast { }
108+
99109 /// A pointer cast which preserves or shrinks the set of referent bytes of
100110 /// a statically-sized referent.
101111 ///
@@ -122,6 +132,37 @@ pub mod cast {
122132 // SAFETY: The `Project::project` impl preserves referent address.
123133 unsafe impl < Src , Dst > Cast < Src , Dst > for CastSized { }
124134
135+ /// A pointer cast which preserves the set of referent bytes of a
136+ /// statically-sized referent.
137+ ///
138+ /// # Safety
139+ ///
140+ /// The implementation of [`Project`] uses a compile-time assertion to
141+ /// guarantee that `Dst` has the same size as `Src`. Thus, `CastSizedExact`
142+ /// has a sound implementation of [`Project`] for all `Src` and `Dst` – the
143+ /// caller may pass any `Src` and `Dst` without being responsible for
144+ /// soundness.
145+ #[ allow( missing_debug_implementations, missing_copy_implementations) ]
146+ pub enum CastSizedExact { }
147+
148+ // SAFETY: By the `static_assert!`, `Dst` has the same size as `Src`,
149+ // and so all casts preserve the set of referent bytes. All operations
150+ // preserve provenance.
151+ unsafe impl < Src , Dst > Project < Src , Dst > for CastSizedExact {
152+ #[ inline( always) ]
153+ fn project ( src : PtrInner < ' _ , Src > ) -> * mut Dst {
154+ static_assert ! ( Src , Dst => mem:: size_of:: <Src >( ) == mem:: size_of:: <Dst >( ) ) ;
155+ src. as_ptr ( ) . cast :: < Dst > ( )
156+ }
157+ }
158+
159+ // SAFETY: The `Project::project_raw` impl preserves referent address.
160+ unsafe impl < Src , Dst > Cast < Src , Dst > for CastSizedExact { }
161+
162+ // SAFETY: By the `static_assert!`, `Project::project_raw` impl preserves
163+ // referent size.
164+ unsafe impl < Src , Dst > CastExact < Src , Dst > for CastSizedExact { }
165+
125166 /// A pointer cast which preserves or shrinks the set of referent bytes of
126167 /// a dynamically-sized referent.
127168 ///
@@ -138,19 +179,19 @@ pub mod cast {
138179 // SAFETY: By the `static_assert!`, `Src` and `Dst` are either:
139180 // - Both sized and equal in size
140181 // - Both slice DSTs with the same trailing slice offset and element size
141- // and with align_of::<Src>() >= align_of::<Dst>(). These ensure that any
142- // given pointer metadata encodes the same size or more size for `Src`
143- // than for `Dst` (note that the alignment is required as it affects the
144- // amount of trailing padding). Thus, `project` preserves or shrinks the
145- // set of referent bytes.
182+ // and with align_of::<Src>() == align_of::<Dst>(). These ensure that any
183+ // given pointer metadata encodes the same size for both `Src` and `Dst`
184+ // (note that the alignment is required as it affects the amount of
185+ // trailing padding). Thus, `project` preserves the set of referent bytes.
146186 unsafe impl < Src , Dst > Project < Src , Dst > for CastUnsized
147187 where
148188 Src : ?Sized + KnownLayout ,
149189 Dst : ?Sized + KnownLayout < PointerMetadata = Src :: PointerMetadata > ,
150190 {
151191 #[ inline( always) ]
152192 fn project ( src : PtrInner < ' _ , Src > ) -> * mut Dst {
153- // FIXME: Do we want this to support shrinking casts as well?
193+ // FIXME: Do we want this to support shrinking casts as well? If so,
194+ // we'll need to remove the `CastExact` impl.
154195 static_assert ! ( Src : ?Sized + KnownLayout , Dst : ?Sized + KnownLayout => {
155196 let src = <Src as KnownLayout >:: LAYOUT ;
156197 let dst = <Dst as KnownLayout >:: LAYOUT ;
@@ -159,7 +200,7 @@ pub mod cast {
159200 (
160201 SizeInfo :: SliceDst ( TrailingSliceLayout { offset: src_offset, elem_size: src_elem_size } ) ,
161202 SizeInfo :: SliceDst ( TrailingSliceLayout { offset: dst_offset, elem_size: dst_elem_size } )
162- ) => src. align. get( ) > = dst. align. get( ) && src_offset == dst_offset && src_elem_size == dst_elem_size,
203+ ) => src. align. get( ) = = dst. align. get( ) && src_offset == dst_offset && src_elem_size == dst_elem_size,
163204 _ => false ,
164205 }
165206 } ) ;
@@ -177,6 +218,20 @@ pub mod cast {
177218 {
178219 }
179220
221+ // SAFETY: By the `static_assert!` in `Project::project`, `Src` and `Dst`
222+ // are either:
223+ // - Both sized and equal in size
224+ // - Both slice DSTs with the same alignment, trailing slice offset, and
225+ // element size. These ensure that any given pointer metadata encodes the
226+ // same size for both `Src` and `Dst` (note that the alignment is required
227+ // as it affects the amount of trailing padding).
228+ unsafe impl < Src , Dst > CastExact < Src , Dst > for CastUnsized
229+ where
230+ Src : ?Sized + KnownLayout ,
231+ Dst : ?Sized + KnownLayout < PointerMetadata = Src :: PointerMetadata > ,
232+ {
233+ }
234+
180235 /// A field projection
181236 ///
182237 /// A `Projection` is a [`Project`] which implements projection by
@@ -246,6 +301,19 @@ pub mod cast {
246301 {
247302 }
248303
304+ // SAFETY: Since the `Project::project` impl delegates to `TU::project` and
305+ // `UV::project`, and since `TU` and `UV` are `CastExact`, the `Project::project`
306+ // impl preserves the set of referent bytes.
307+ unsafe impl < T , U , V , TU , UV > CastExact < T , V > for TransitiveProject < U , TU , UV >
308+ where
309+ T : ?Sized ,
310+ U : ?Sized ,
311+ V : ?Sized ,
312+ TU : CastExact < T , U > ,
313+ UV : CastExact < U , V > ,
314+ {
315+ }
316+
249317 /// A cast from `T` to `[u8]`.
250318 pub ( crate ) struct AsBytesCast ;
251319
@@ -275,4 +343,7 @@ pub mod cast {
275343
276344 // SAFETY: The `Project::project` impl preserves referent address.
277345 unsafe impl < T : ?Sized + KnownLayout > Cast < T , [ u8 ] > for AsBytesCast { }
346+
347+ // SAFETY: The `Project::project` impl preserves the set of referent bytes.
348+ unsafe impl < T : ?Sized + KnownLayout > CastExact < T , [ u8 ] > for AsBytesCast { }
278349}
0 commit comments