diff options
Diffstat (limited to 'vendor/bytemuck/src/transparent.rs')
-rw-r--r-- | vendor/bytemuck/src/transparent.rs | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/vendor/bytemuck/src/transparent.rs b/vendor/bytemuck/src/transparent.rs new file mode 100644 index 0000000..5b9fe0e --- /dev/null +++ b/vendor/bytemuck/src/transparent.rs @@ -0,0 +1,288 @@ +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. (When deriving +/// `TransparentWrapper` on a type with ZST fields, the ZST fields must be +/// [`Zeroable`]). +/// +/// 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); +/// ``` +/// +/// ## Deriving +/// +/// When deriving, the non-wrapped fields must uphold all the normal requirements, +/// and must also be `Zeroable`. +/// +#[cfg_attr(feature = "derive", doc = "```")] +#[cfg_attr( + not(feature = "derive"), + doc = "```ignore +// This example requires the `derive` feature." +)] +/// use bytemuck::TransparentWrapper; +/// use std::marker::PhantomData; +/// +/// #[derive(TransparentWrapper)] +/// #[repr(transparent)] +/// #[transparent(usize)] +/// struct Wrapper<T: ?Sized>(usize, PhantomData<T>); // PhantomData<T> implements Zeroable for all T +/// ``` +/// +/// Here, an error will occur, because `MyZst` does not implement `Zeroable`. +/// +#[cfg_attr(feature = "derive", doc = "```compile_fail")] +#[cfg_attr( + not(feature = "derive"), + doc = "```ignore +// This example requires the `derive` feature." +)] +/// use bytemuck::TransparentWrapper; +/// struct MyZst; +/// +/// #[derive(TransparentWrapper)] +/// #[repr(transparent)] +/// #[transparent(usize)] +/// struct Wrapper(usize, MyZst); // MyZst does not implement Zeroable +/// ``` +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> {} |