Skip to content

Commit 75208cb

Browse files
committed
[pointer][transmute] Migrate from util
This prepares us to rename `TransparentWrapper` to `TransmuteFrom`, which we'll do in a follow-up commit to preserve nice git diffs. Makes progress on #1122 gherrit-pr-id: Ifc49755af0d90eeefe7822d755d508403c266bda
1 parent 08771d7 commit 75208cb

File tree

5 files changed

+469
-458
lines changed

5 files changed

+469
-458
lines changed

src/pointer/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod inner;
1212
#[doc(hidden)]
1313
pub mod invariant;
1414
mod ptr;
15+
pub(crate) mod transmute;
1516

1617
#[doc(hidden)]
1718
pub use invariant::{BecauseExclusive, BecauseImmutable, Read};

src/pointer/ptr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ mod _external {
172172
/// Methods for converting to and from `Ptr` and Rust's safe reference types.
173173
mod _conversions {
174174
use super::*;
175-
use crate::util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance};
175+
use crate::pointer::transmute::{
176+
AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance,
177+
};
176178

177179
/// `&'a T` → `Ptr<'a, T>`
178180
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>

src/pointer/transmute.rs

Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
// Copyright 2024 The Fuchsia Authors
2+
//
3+
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4+
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5+
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6+
// This file may not be copied, modified, or distributed except according to
7+
// those terms.
8+
9+
use core::{
10+
cell::UnsafeCell,
11+
mem::{ManuallyDrop, MaybeUninit},
12+
num::Wrapping,
13+
};
14+
15+
use crate::{
16+
pointer::invariant::{self, Invariants},
17+
Unalign,
18+
};
19+
20+
/// A type which has the same layout as the type it wraps.
21+
///
22+
/// # Safety
23+
///
24+
/// `T: TransparentWrapper` implies that `T` has the same size as [`T::Inner`].
25+
/// Further, `T: TransparentWrapper<I>` implies that:
26+
/// - If `T::UnsafeCellVariance = Covariant`, then `T` has `UnsafeCell`s
27+
/// covering the same byte ranges as `T::Inner`.
28+
/// - If a `T` pointer satisfies the alignment invariant `I::Alignment`, then
29+
/// that same pointer, cast to `T::Inner`, satisfies the alignment invariant
30+
/// `<T::AlignmentVariance as AlignmentVariance<I::Alignment>>::Applied`.
31+
/// - If a `T` pointer satisfies the validity invariant `I::Validity`, then that
32+
/// same pointer, cast to `T::Inner`, satisfies the validity invariant
33+
/// `<T::ValidityVariance as ValidityVariance<I::Validity>>::Applied`.
34+
///
35+
/// [`T::Inner`]: TransparentWrapper::Inner
36+
/// [`UnsafeCell`]: core::cell::UnsafeCell
37+
/// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance
38+
/// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance
39+
#[doc(hidden)]
40+
pub unsafe trait TransparentWrapper<I: Invariants> {
41+
type Inner: ?Sized;
42+
43+
type UnsafeCellVariance;
44+
type AlignmentVariance: AlignmentVariance<I::Alignment>;
45+
type ValidityVariance: ValidityVariance<I::Validity>;
46+
47+
/// Casts a wrapper pointer to an inner pointer.
48+
///
49+
/// # Safety
50+
///
51+
/// The resulting pointer has the same address and provenance as `ptr`, and
52+
/// addresses the same number of bytes.
53+
fn cast_into_inner(ptr: *mut Self) -> *mut Self::Inner;
54+
55+
/// Casts an inner pointer to a wrapper pointer.
56+
///
57+
/// # Safety
58+
///
59+
/// The resulting pointer has the same address and provenance as `ptr`, and
60+
/// addresses the same number of bytes.
61+
fn cast_from_inner(ptr: *mut Self::Inner) -> *mut Self;
62+
}
63+
64+
#[allow(unreachable_pub)]
65+
#[doc(hidden)]
66+
pub trait AlignmentVariance<I: invariant::Alignment> {
67+
type Applied: invariant::Alignment;
68+
}
69+
70+
#[allow(unreachable_pub)]
71+
#[doc(hidden)]
72+
pub trait ValidityVariance<I: invariant::Validity> {
73+
type Applied: invariant::Validity;
74+
}
75+
76+
#[doc(hidden)]
77+
#[allow(missing_copy_implementations, missing_debug_implementations)]
78+
pub enum Covariant {}
79+
80+
impl<I: invariant::Alignment> AlignmentVariance<I> for Covariant {
81+
type Applied = I;
82+
}
83+
84+
impl<I: invariant::Validity> ValidityVariance<I> for Covariant {
85+
type Applied = I;
86+
}
87+
88+
#[doc(hidden)]
89+
#[allow(missing_copy_implementations, missing_debug_implementations)]
90+
pub enum Invariant {}
91+
92+
impl<I: invariant::Alignment> AlignmentVariance<I> for Invariant {
93+
type Applied = invariant::Unknown;
94+
}
95+
96+
impl<I: invariant::Validity> ValidityVariance<I> for Invariant {
97+
type Applied = invariant::Unknown;
98+
}
99+
100+
// SAFETY:
101+
// - Per [1], `MaybeUninit<T>` has the same size as `T`.
102+
// - See inline comments for other safety justifications.
103+
//
104+
// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
105+
//
106+
// `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
107+
// `T`
108+
unsafe impl<T, I: Invariants> TransparentWrapper<I> for MaybeUninit<T> {
109+
type Inner = T;
110+
111+
// SAFETY: `MaybeUninit<T>` has `UnsafeCell`s covering the same byte ranges
112+
// as `Inner = T`. This is not explicitly documented, but it can be
113+
// inferred. Per [1] in the preceding safety comment, `MaybeUninit<T>` has
114+
// the same size as `T`. Further, note the signature of
115+
// `MaybeUninit::assume_init_ref` [2]:
116+
//
117+
// pub unsafe fn assume_init_ref(&self) -> &T
118+
//
119+
// If the argument `&MaybeUninit<T>` and the returned `&T` had `UnsafeCell`s
120+
// at different offsets, this would be unsound. Its existence is proof that
121+
// this is not the case.
122+
//
123+
// [2] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref
124+
type UnsafeCellVariance = Covariant;
125+
// SAFETY: Per [1], `MaybeUninit<T>` has the same layout as `T`, and thus
126+
// has the same alignment as `T`.
127+
//
128+
// [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1:
129+
//
130+
// `MaybeUninit<T>` is guaranteed to have the same size, alignment, and
131+
// ABI as `T`.
132+
type AlignmentVariance = Covariant;
133+
// SAFETY: `MaybeUninit` has no validity invariants. Thus, a valid
134+
// `MaybeUninit<T>` is not necessarily a valid `T`.
135+
type ValidityVariance = Invariant;
136+
137+
#[inline(always)]
138+
fn cast_into_inner(ptr: *mut MaybeUninit<T>) -> *mut T {
139+
// SAFETY: Per [1] (from comment above), `MaybeUninit<T>` has the same
140+
// layout as `T`. Thus, this cast preserves size.
141+
//
142+
// This cast trivially preserves provenance.
143+
ptr.cast::<T>()
144+
}
145+
146+
#[inline(always)]
147+
fn cast_from_inner(ptr: *mut T) -> *mut MaybeUninit<T> {
148+
// SAFETY: Per [1] (from comment above), `MaybeUninit<T>` has the same
149+
// layout as `T`. Thus, this cast preserves size.
150+
//
151+
// This cast trivially preserves provenance.
152+
ptr.cast::<MaybeUninit<T>>()
153+
}
154+
}
155+
156+
// SAFETY:
157+
// - Per [1], `ManuallyDrop<T>` has the same size as `T`.
158+
// - See inline comments for other safety justifications.
159+
//
160+
// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
161+
//
162+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
163+
// `T`
164+
unsafe impl<T: ?Sized, I: Invariants> TransparentWrapper<I> for ManuallyDrop<T> {
165+
type Inner = T;
166+
167+
// SAFETY: Per [1], `ManuallyDrop<T>` has `UnsafeCell`s covering the same
168+
// byte ranges as `Inner = T`.
169+
//
170+
// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
171+
//
172+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
173+
// validity as `T`, and is subject to the same layout optimizations as
174+
// `T`. As a consequence, it has no effect on the assumptions that the
175+
// compiler makes about its contents.
176+
type UnsafeCellVariance = Covariant;
177+
// SAFETY: Per [1], `ManuallyDrop<T>` has the same layout as `T`, and thus
178+
// has the same alignment as `T`.
179+
//
180+
// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html:
181+
//
182+
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
183+
// validity as `T`
184+
type AlignmentVariance = Covariant;
185+
186+
// SAFETY: Per [1] (from comment above), `ManuallyDrop<T>` has the same bit
187+
// validity as `T`.
188+
type ValidityVariance = Covariant;
189+
190+
#[inline(always)]
191+
fn cast_into_inner(ptr: *mut ManuallyDrop<T>) -> *mut T {
192+
// SAFETY: Per [1] (from comment above), `ManuallyDrop<T>` has the same
193+
// layout as `T`. Thus, this cast preserves size even if `T` is unsized.
194+
//
195+
// This cast trivially preserves provenance.
196+
#[allow(clippy::as_conversions)]
197+
return ptr as *mut T;
198+
}
199+
200+
#[inline(always)]
201+
fn cast_from_inner(ptr: *mut T) -> *mut ManuallyDrop<T> {
202+
// SAFETY: Per [1] (from comment above), `ManuallyDrop<T>` has the same
203+
// layout as `T`. Thus, this cast preserves size even if `T` is unsized.
204+
//
205+
// This cast trivially preserves provenance.
206+
#[allow(clippy::as_conversions)]
207+
return ptr as *mut ManuallyDrop<T>;
208+
}
209+
}
210+
211+
// SAFETY:
212+
// - Per [1], `Wrapping<T>` has the same size as `T`.
213+
// - See inline comments for other safety justifications.
214+
//
215+
// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1:
216+
//
217+
// `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
218+
unsafe impl<T, I: Invariants> TransparentWrapper<I> for Wrapping<T> {
219+
type Inner = T;
220+
221+
// SAFETY: Per [1], `Wrapping<T>` has the same layout as `T`. Since its
222+
// single field (of type `T`) is public, it would be a breaking change to
223+
// add or remove fields. Thus, we know that `Wrapping<T>` contains a `T` (as
224+
// opposed to just having the same size and alignment as `T`) with no pre-
225+
// or post-padding. Thus, `Wrapping<T>` must have `UnsafeCell`s covering the
226+
// same byte ranges as `Inner = T`.
227+
//
228+
// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1:
229+
//
230+
// `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
231+
type UnsafeCellVariance = Covariant;
232+
// SAFETY: Per [1], `Wrapping<T>` has the same layout as `T`, and thus has
233+
// the same alignment as `T`.
234+
//
235+
// [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1:
236+
//
237+
// `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
238+
type AlignmentVariance = Covariant;
239+
240+
// SAFETY: `Wrapping<T>` has only one field, which is `pub` [2]. We are also
241+
// guaranteed per [1] (from the comment above) that `Wrapping<T>` has the
242+
// same layout as `T`. The only way for both of these to be true
243+
// simultaneously is for `Wrapping<T>` to have the same bit validity as `T`.
244+
// In particular, in order to change the bit validity, one of the following
245+
// would need to happen:
246+
// - `Wrapping` could change its `repr`, but this would violate the layout
247+
// guarantee.
248+
// - `Wrapping` could add or change its fields, but this would be a
249+
// stability-breaking change.
250+
//
251+
// [2] https://doc.rust-lang.org/core/num/struct.Wrapping.html
252+
type ValidityVariance = Covariant;
253+
254+
#[inline(always)]
255+
fn cast_into_inner(ptr: *mut Wrapping<T>) -> *mut T {
256+
// SAFETY: Per [1] (from comment above), `Wrapping<T>` has the same
257+
// layout as `T`. Thus, this cast preserves size.
258+
//
259+
// This cast trivially preserves provenance.
260+
ptr.cast::<T>()
261+
}
262+
263+
#[inline(always)]
264+
fn cast_from_inner(ptr: *mut T) -> *mut Wrapping<T> {
265+
// SAFETY: Per [1] (from comment above), `Wrapping<T>` has the same
266+
// layout as `T`. Thus, this cast preserves size.
267+
//
268+
// This cast trivially preserves provenance.
269+
ptr.cast::<Wrapping<T>>()
270+
}
271+
}
272+
273+
// SAFETY:
274+
// - Per [1], `UnsafeCell<T>` has the same size as `T`.
275+
// - See inline comments for other safety justifications.
276+
//
277+
// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
278+
//
279+
// `UnsafeCell<T>` has the same in-memory representation as its inner type
280+
// `T`.
281+
unsafe impl<T: ?Sized, I: Invariants> TransparentWrapper<I> for UnsafeCell<T> {
282+
type Inner = T;
283+
284+
// SAFETY: Since we set this to `Invariant`, we make no safety claims.
285+
type UnsafeCellVariance = Invariant;
286+
287+
// SAFETY: Per [1] (from comment on impl), `Unalign<T>` has the same
288+
// representation as `T`, and thus has the same alignment as `T`.
289+
type AlignmentVariance = Covariant;
290+
291+
// SAFETY: Per [1], `Unalign<T>` has the same bit validity as `T`.
292+
// Technically the term "representation" doesn't guarantee this, but the
293+
// subsequent sentence in the documentation makes it clear that this is the
294+
// intention.
295+
//
296+
// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
297+
//
298+
// `UnsafeCell<T>` has the same in-memory representation as its inner type
299+
// `T`. A consequence of this guarantee is that it is possible to convert
300+
// between `T` and `UnsafeCell<T>`.
301+
type ValidityVariance = Covariant;
302+
303+
#[inline(always)]
304+
fn cast_into_inner(ptr: *mut UnsafeCell<T>) -> *mut T {
305+
// SAFETY: Per [1] (from comment above), `UnsafeCell<T>` has the same
306+
// representation as `T`. Thus, this cast preserves size.
307+
//
308+
// This cast trivially preserves provenance.
309+
#[allow(clippy::as_conversions)]
310+
return ptr as *mut T;
311+
}
312+
313+
#[inline(always)]
314+
fn cast_from_inner(ptr: *mut T) -> *mut UnsafeCell<T> {
315+
// SAFETY: Per [1] (from comment above), `UnsafeCell<T>` has the same
316+
// representation as `T`. Thus, this cast preserves size.
317+
//
318+
// This cast trivially preserves provenance.
319+
#[allow(clippy::as_conversions)]
320+
return ptr as *mut UnsafeCell<T>;
321+
}
322+
}
323+
324+
// SAFETY: `Unalign<T>` promises to have the same size as `T`.
325+
//
326+
// See inline comments for other safety justifications.
327+
unsafe impl<T, I: Invariants> TransparentWrapper<I> for Unalign<T> {
328+
type Inner = T;
329+
330+
// SAFETY: `Unalign<T>` promises to have `UnsafeCell`s covering the same
331+
// byte ranges as `Inner = T`.
332+
type UnsafeCellVariance = Covariant;
333+
334+
// SAFETY: Since `Unalign<T>` promises to have alignment 1 regardless of
335+
// `T`'s alignment. Thus, an aligned pointer to `Unalign<T>` is not
336+
// necessarily an aligned pointer to `T`.
337+
type AlignmentVariance = Invariant;
338+
339+
// SAFETY: `Unalign<T>` promises to have the same validity as `T`.
340+
type ValidityVariance = Covariant;
341+
342+
#[inline(always)]
343+
fn cast_into_inner(ptr: *mut Unalign<T>) -> *mut T {
344+
// SAFETY: Per the safety comment on the impl block, `Unalign<T>` has
345+
// the size as `T`. Thus, this cast preserves size.
346+
//
347+
// This cast trivially preserves provenance.
348+
ptr.cast::<T>()
349+
}
350+
351+
#[inline(always)]
352+
fn cast_from_inner(ptr: *mut T) -> *mut Unalign<T> {
353+
// SAFETY: Per the safety comment on the impl block, `Unalign<T>` has
354+
// the size as `T`. Thus, this cast preserves size.
355+
//
356+
// This cast trivially preserves provenance.
357+
ptr.cast::<Unalign<T>>()
358+
}
359+
}

0 commit comments

Comments
 (0)