250 lines
8.7 KiB
Rust
250 lines
8.7 KiB
Rust
use super::*;
|
|
|
|
/// A trait which indicates that a type is a `#[repr(transparent)]` wrapper
|
|
/// around the `Inner` value.
|
|
///
|
|
/// This allows safely copy transmuting between the `Inner` type and the
|
|
/// `TransparentWrapper` type. Functions like `wrap_{}` convert from the inner
|
|
/// type to the wrapper type and `peel_{}` functions do the inverse conversion
|
|
/// from the wrapper type to the inner type. We deliberately do not call the
|
|
/// wrapper-removing methods "unwrap" because at this point that word is too
|
|
/// strongly tied to the Option/ Result methods.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// The safety contract of `TransparentWrapper` is relatively simple:
|
|
///
|
|
/// For a given `Wrapper` which implements `TransparentWrapper<Inner>`:
|
|
///
|
|
/// 1. `Wrapper` must be a wrapper around `Inner` with an identical data
|
|
/// representations. This either means that it must be a
|
|
/// `#[repr(transparent)]` struct which contains a either a field of type
|
|
/// `Inner` (or a field of some other transparent wrapper for `Inner`) as
|
|
/// the only non-ZST field.
|
|
///
|
|
/// 2. Any fields *other* than the `Inner` field must be trivially constructable
|
|
/// ZSTs, for example `PhantomData`, `PhantomPinned`, etc.
|
|
///
|
|
/// 3. The `Wrapper` may not impose additional alignment requirements over
|
|
/// `Inner`.
|
|
/// - Note: this is currently guaranteed by `repr(transparent)`, but there
|
|
/// have been discussions of lifting it, so it's stated here explicitly.
|
|
///
|
|
/// 4. All functions on `TransparentWrapper` **may not** be overridden.
|
|
///
|
|
/// ## Caveats
|
|
///
|
|
/// If the wrapper imposes additional constraints upon the inner type which are
|
|
/// required for safety, it's responsible for ensuring those still hold -- this
|
|
/// generally requires preventing access to instances of the inner type, as
|
|
/// implementing `TransparentWrapper<U> for T` means anybody can call
|
|
/// `T::cast_ref(any_instance_of_u)`.
|
|
///
|
|
/// For example, it would be invalid to implement TransparentWrapper for `str`
|
|
/// to implement `TransparentWrapper` around `[u8]` because of this.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ## Basic
|
|
///
|
|
/// ```
|
|
/// use bytemuck::TransparentWrapper;
|
|
/// # #[derive(Default)]
|
|
/// # struct SomeStruct(u32);
|
|
///
|
|
/// #[repr(transparent)]
|
|
/// struct MyWrapper(SomeStruct);
|
|
///
|
|
/// unsafe impl TransparentWrapper<SomeStruct> for MyWrapper {}
|
|
///
|
|
/// // interpret a reference to &SomeStruct as a &MyWrapper
|
|
/// let thing = SomeStruct::default();
|
|
/// let inner_ref: &MyWrapper = MyWrapper::wrap_ref(&thing);
|
|
///
|
|
/// // Works with &mut too.
|
|
/// let mut mut_thing = SomeStruct::default();
|
|
/// let inner_mut: &mut MyWrapper = MyWrapper::wrap_mut(&mut mut_thing);
|
|
///
|
|
/// # let _ = (inner_ref, inner_mut); // silence warnings
|
|
/// ```
|
|
///
|
|
/// ## Use with dynamically sized types
|
|
///
|
|
/// ```
|
|
/// use bytemuck::TransparentWrapper;
|
|
///
|
|
/// #[repr(transparent)]
|
|
/// struct Slice<T>([T]);
|
|
///
|
|
/// unsafe impl<T> TransparentWrapper<[T]> for Slice<T> {}
|
|
///
|
|
/// let s = Slice::wrap_ref(&[1u32, 2, 3]);
|
|
/// assert_eq!(&s.0, &[1, 2, 3]);
|
|
///
|
|
/// let mut buf = [1, 2, 3u8];
|
|
/// let sm = Slice::wrap_mut(&mut buf);
|
|
/// ```
|
|
pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
|
/// Convert the inner type into the wrapper type.
|
|
#[inline]
|
|
fn wrap(s: Inner) -> Self
|
|
where
|
|
Self: Sized,
|
|
Inner: Sized,
|
|
{
|
|
// SAFETY: The unsafe contract requires that `Self` and `Inner` have
|
|
// identical representations.
|
|
unsafe { transmute!(s) }
|
|
}
|
|
|
|
/// Convert a reference to the inner type into a reference to the wrapper
|
|
/// type.
|
|
#[inline]
|
|
fn wrap_ref(s: &Inner) -> &Self {
|
|
unsafe {
|
|
assert!(size_of::<*const Inner>() == size_of::<*const Self>());
|
|
// A pointer cast doesn't work here because rustc can't tell that
|
|
// the vtables match (because of the `?Sized` restriction relaxation).
|
|
// A `transmute` doesn't work because the sizes are unspecified.
|
|
//
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations.
|
|
let inner_ptr = s as *const Inner;
|
|
let wrapper_ptr: *const Self = transmute!(inner_ptr);
|
|
&*wrapper_ptr
|
|
}
|
|
}
|
|
|
|
/// Convert a mutable reference to the inner type into a mutable reference to
|
|
/// the wrapper type.
|
|
#[inline]
|
|
fn wrap_mut(s: &mut Inner) -> &mut Self {
|
|
unsafe {
|
|
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
|
// A pointer cast doesn't work here because rustc can't tell that
|
|
// the vtables match (because of the `?Sized` restriction relaxation).
|
|
// A `transmute` doesn't work because the sizes are unspecified.
|
|
//
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations.
|
|
let inner_ptr = s as *mut Inner;
|
|
let wrapper_ptr: *mut Self = transmute!(inner_ptr);
|
|
&mut *wrapper_ptr
|
|
}
|
|
}
|
|
|
|
/// Convert a slice to the inner type into a slice to the wrapper type.
|
|
#[inline]
|
|
fn wrap_slice(s: &[Inner]) -> &[Self]
|
|
where
|
|
Self: Sized,
|
|
Inner: Sized,
|
|
{
|
|
unsafe {
|
|
assert!(size_of::<*const Inner>() == size_of::<*const Self>());
|
|
assert!(align_of::<*const Inner>() == align_of::<*const Self>());
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations (size and alignment).
|
|
core::slice::from_raw_parts(s.as_ptr() as *const Self, s.len())
|
|
}
|
|
}
|
|
|
|
/// Convert a mutable slice to the inner type into a mutable slice to the
|
|
/// wrapper type.
|
|
#[inline]
|
|
fn wrap_slice_mut(s: &mut [Inner]) -> &mut [Self]
|
|
where
|
|
Self: Sized,
|
|
Inner: Sized,
|
|
{
|
|
unsafe {
|
|
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
|
assert!(align_of::<*mut Inner>() == align_of::<*mut Self>());
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations (size and alignment).
|
|
core::slice::from_raw_parts_mut(s.as_mut_ptr() as *mut Self, s.len())
|
|
}
|
|
}
|
|
|
|
/// Convert the wrapper type into the inner type.
|
|
#[inline]
|
|
fn peel(s: Self) -> Inner
|
|
where
|
|
Self: Sized,
|
|
Inner: Sized,
|
|
{
|
|
unsafe { transmute!(s) }
|
|
}
|
|
|
|
/// Convert a reference to the wrapper type into a reference to the inner
|
|
/// type.
|
|
#[inline]
|
|
fn peel_ref(s: &Self) -> &Inner {
|
|
unsafe {
|
|
assert!(size_of::<*const Inner>() == size_of::<*const Self>());
|
|
// A pointer cast doesn't work here because rustc can't tell that
|
|
// the vtables match (because of the `?Sized` restriction relaxation).
|
|
// A `transmute` doesn't work because the sizes are unspecified.
|
|
//
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations.
|
|
let wrapper_ptr = s as *const Self;
|
|
let inner_ptr: *const Inner = transmute!(wrapper_ptr);
|
|
&*inner_ptr
|
|
}
|
|
}
|
|
|
|
/// Convert a mutable reference to the wrapper type into a mutable reference
|
|
/// to the inner type.
|
|
#[inline]
|
|
fn peel_mut(s: &mut Self) -> &mut Inner {
|
|
unsafe {
|
|
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
|
// A pointer cast doesn't work here because rustc can't tell that
|
|
// the vtables match (because of the `?Sized` restriction relaxation).
|
|
// A `transmute` doesn't work because the sizes are unspecified.
|
|
//
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations.
|
|
let wrapper_ptr = s as *mut Self;
|
|
let inner_ptr: *mut Inner = transmute!(wrapper_ptr);
|
|
&mut *inner_ptr
|
|
}
|
|
}
|
|
|
|
/// Convert a slice to the wrapped type into a slice to the inner type.
|
|
#[inline]
|
|
fn peel_slice(s: &[Self]) -> &[Inner]
|
|
where
|
|
Self: Sized,
|
|
Inner: Sized,
|
|
{
|
|
unsafe {
|
|
assert!(size_of::<*const Inner>() == size_of::<*const Self>());
|
|
assert!(align_of::<*const Inner>() == align_of::<*const Self>());
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations (size and alignment).
|
|
core::slice::from_raw_parts(s.as_ptr() as *const Inner, s.len())
|
|
}
|
|
}
|
|
|
|
/// Convert a mutable slice to the wrapped type into a mutable slice to the
|
|
/// inner type.
|
|
#[inline]
|
|
fn peel_slice_mut(s: &mut [Self]) -> &mut [Inner]
|
|
where
|
|
Self: Sized,
|
|
Inner: Sized,
|
|
{
|
|
unsafe {
|
|
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
|
|
assert!(align_of::<*mut Inner>() == align_of::<*mut Self>());
|
|
// SAFETY: The unsafe contract requires that these two have
|
|
// identical representations (size and alignment).
|
|
core::slice::from_raw_parts_mut(s.as_mut_ptr() as *mut Inner, s.len())
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<T> TransparentWrapper<T> for core::num::Wrapping<T> {}
|