[Feature] extend TransparentWrapper conversion functions (#58)

* update rustfmt.toml

replace `merge_imports = true` (deprecated) with `imports_granularity = "Crate"`

* run `cargo +nightly fmt`

* rewrite docs and rename `Wrapped` to `Inner`

rewriting some docs for conciseness

rename `Wrapped` to `Inner`, because it's hard to visually differentiate between
`Wrapper` and `Wrapped`

* impl missing `TransparentWrapper::wrap_{}` fns

Implement 3 new wrapping functions on `TransparentWrapper` providing new
conversions.

- `TransparentWrapper::wrap(s: Inner) -> Self`
- `TransparentWrapper::wrap_slice(s: &[Inner]) -> &[Self]`
- `TransparentWrapper::wrap_slice_mut(s: &mut [Inner]) -> &mut [Self]`

* impl `TransparentWrapper::unwrap_{}` fns

Implement counterparts to `TransparentWrapper::wrap_{}` functions
providing reverse conversions.

- `TransparentWrapper::unwrap(self) -> Inner`
- `TransparentWrapper::unwrap_ref(&self) -> &Inner`
- `TransparentWrapper::unwrap_mut(&mut self) -> &mut Inner`
- `TransparentWrapper::unwrap_slice(s: &[Self]) -> &[Inner]`
- `TransparentWrapper::unwrap_slice_mut(s: &mut [Self]) -> &mut [Inner]`

* add `TransparentWrapper` UB test

This test is only for MIRI to check all trait functions on
`TransparentWrapper` if they cause any UB.
The output of the functions is not checked.

* small `TransparentWrapper` doc adjustments

* change fn signature on `TransparentWrapper`

Methods on `TransparentWrapper` trait are now associated functions.
They now take `Self` instead of `self` as argument)

- `TransparentWrapper::unwrap(s: Self)`
- `TransparentWrapper::unwrap_ref(s: &Self)`
- `TransparentWrapper::unwrap_mut(s: &mut Self)`
This commit is contained in:
Luis Wirth 2021-03-29 07:11:13 +02:00 committed by GitHub
parent 08a4b8fbc2
commit 30a96066fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 288 additions and 78 deletions

View File

@ -12,5 +12,5 @@ use_small_heuristics = "Max"
# Unstable # Unstable
format_code_in_doc_comments = true format_code_in_doc_comments = true
merge_imports = true imports_granularity = "Crate"
wrap_comments = true wrap_comments = true

View File

@ -85,8 +85,8 @@ pub unsafe trait Contiguous: Copy + 'static {
/// `#[repr(Int)]` or `#[repr(C)]` attribute, (if it does not, it is /// `#[repr(Int)]` or `#[repr(C)]` attribute, (if it does not, it is
/// *unsound* to implement `Contiguous`!). /// *unsound* to implement `Contiguous`!).
/// ///
/// - For `#[repr(Int)]`, use the listed `Int`. e.g. `#[repr(u8)]` should /// - For `#[repr(Int)]`, use the listed `Int`. e.g. `#[repr(u8)]` should use
/// use `type Int = u8`. /// `type Int = u8`.
/// ///
/// - For `#[repr(C)]`, use whichever type the C compiler will use to /// - For `#[repr(C)]`, use whichever type the C compiler will use to
/// represent the given enum. This is usually `c_int` (from `std::os::raw` /// represent the given enum. This is usually `c_int` (from `std::os::raw`

View File

@ -25,7 +25,9 @@
/// # use bytemuck::offset_of; /// # use bytemuck::offset_of;
/// // enums can't derive default, and for this example we don't pick one /// // enums can't derive default, and for this example we don't pick one
/// enum MyExampleEnum { /// enum MyExampleEnum {
/// A, B, C, /// A,
/// B,
/// C,
/// } /// }
/// ///
/// // so now our struct here doesn't have Default /// // so now our struct here doesn't have Default
@ -65,11 +67,11 @@
/// [rust-lang/rust#27060]: https://github.com/rust-lang/rust/issues/27060 /// [rust-lang/rust#27060]: https://github.com/rust-lang/rust/issues/27060
/// ///
/// <p style="background:rgba(255,181,77,0.16);padding:0.75em;"> /// <p style="background:rgba(255,181,77,0.16);padding:0.75em;">
/// <strong>Warning:</strong> This is only true for versions of bytemuck > 1.4.0. /// <strong>Warning:</strong> This is only true for versions of bytemuck >
/// Previous versions of /// 1.4.0. Previous versions of
/// <code style="background:rgba(41,24,0,0.1);">bytemuck::offset_of!</code> /// <code style="background:rgba(41,24,0,0.1);">bytemuck::offset_of!</code>
/// will only emit a warning when used on the field of a packed struct in safe code, /// will only emit a warning when used on the field of a packed struct in safe
/// which can lead to unsoundness. /// code, which can lead to unsoundness.
/// </p> /// </p>
/// ///
/// For example, the following will fail to compile: /// For example, the following will fail to compile:
@ -91,7 +93,8 @@
/// ```compile_fail /// ```compile_fail
/// # #[repr(C, packed)] #[derive(Default)] struct Example { field: u32 } /// # #[repr(C, packed)] #[derive(Default)] struct Example { field: u32 }
/// // Still doesn't compile: /// // Still doesn't compile:
/// #[allow(safe_packed_borrows)] { /// #[allow(safe_packed_borrows)]
/// {
/// let _offset = bytemuck::offset_of!(Example, field); /// let _offset = bytemuck::offset_of!(Example, field);
/// } /// }
/// ``` /// ```

View File

@ -1,38 +1,42 @@
use super::*; use super::*;
/// A trait which indicates that a type is a `repr(transparent)` wrapper around /// A trait which indicates that a type is a `#[repr(transparent)]` wrapper
/// the `Wrapped` value. /// around the `Inner` value.
/// ///
/// This allows safely creating references to `T` from those to the `Wrapped` /// This allows safely copy transmuting between the `Inner` type and the
/// type, using the `wrap_ref` and `wrap_mut` functions. /// `TransparentWrapper` type.
/// Functions like `wrap_{}` convert from the inner
/// type to the wrapper type and `unwrap_{}` functions do the inverse conversion
/// from the wrapper type to the inner type.
/// ///
/// # Safety /// # Safety
/// ///
/// The safety contract of `TransparentWrapper` is relatively simple: /// The safety contract of `TransparentWrapper` is relatively simple:
/// ///
/// For a given `Wrapper` which implements `TransparentWrapper<Wrapped>`: /// For a given `Wrapper` which implements `TransparentWrapper<Inner>`:
/// ///
/// 1. Wrapper must be a `#[repr(transparent)]` wrapper around `Wrapped`. This /// 1. `Wrapper` must be a wrapper around `Inner` with an identical data
/// either means that it must be a `#[repr(transparent)]` struct which /// representations. This either means that it must be a
/// contains a either a field of type `Wrapped` (or a field of some other /// `#[repr(transparent)]` struct which contains a either a field of type
/// transparent wrapper for `Wrapped`) as the only non-ZST field. /// `Inner` (or a field of some other transparent wrapper for `Inner`) as the
/// only non-ZST field.
/// ///
/// 2. Any fields *other* than the `Wrapped` field must be trivially /// 2. Any fields *other* than the `Inner` field must be trivially
/// constructable ZSTs, for example `PhantomData`, `PhantomPinned`, etc. /// constructable ZSTs, for example `PhantomData`, `PhantomPinned`, etc.
/// ///
/// 3. The `Wrapper` may not impose additional alignment requirements over /// 3. The `Wrapper` may not impose additional alignment requirements over
/// `Wrapped`. /// `Inner`.
/// - Note: this is currently guaranteed by `repr(transparent)`, but there /// - Note: this is currently guaranteed by `repr(transparent)`, but there
/// have been discussions of lifting it, so it's stated here explicitly. /// have been discussions of lifting it, so it's stated here explicitly.
/// ///
/// 4. The `wrap_ref` and `wrap_mut` functions on `TransparentWrapper` may not /// 4. All functions on
/// be overridden. /// `TransparentWrapper` **may not** be overridden.
/// ///
/// ## Caveats /// ## Caveats
/// ///
/// If the wrapper imposes additional constraints upon the wrapped type which /// If the wrapper imposes additional constraints upon the inner type which
/// are required for safety, it's responsible for ensuring those still hold -- /// are required for safety, it's responsible for ensuring those still hold --
/// this generally requires preventing access to instances of the wrapped type, /// this generally requires preventing access to instances of the inner type,
/// as implementing `TransparentWrapper<U> for T` means anybody can call /// as implementing `TransparentWrapper<U> for T` means anybody can call
/// `T::cast_ref(any_instance_of_u)`. /// `T::cast_ref(any_instance_of_u)`.
/// ///
@ -55,13 +59,13 @@ use super::*;
/// ///
/// // interpret a reference to &SomeStruct as a &MyWrapper /// // interpret a reference to &SomeStruct as a &MyWrapper
/// let thing = SomeStruct::default(); /// let thing = SomeStruct::default();
/// let wrapped_ref: &MyWrapper = MyWrapper::wrap_ref(&thing); /// let inner_ref: &MyWrapper = MyWrapper::wrap_ref(&thing);
/// ///
/// // Works with &mut too. /// // Works with &mut too.
/// let mut mut_thing = SomeStruct::default(); /// let mut mut_thing = SomeStruct::default();
/// let wrapped_mut: &mut MyWrapper = MyWrapper::wrap_mut(&mut mut_thing); /// let inner_mut: &mut MyWrapper = MyWrapper::wrap_mut(&mut mut_thing);
/// ///
/// # let _ = (wrapped_ref, wrapped_mut); // silence warnings /// # let _ = (inner_ref, inner_mut); // silence warnings
/// ``` /// ```
/// ///
/// ## Use with dynamically sized types /// ## Use with dynamically sized types
@ -80,56 +84,166 @@ use super::*;
/// let mut buf = [1, 2, 3u8]; /// let mut buf = [1, 2, 3u8];
/// let sm = Slice::wrap_mut(&mut buf); /// let sm = Slice::wrap_mut(&mut buf);
/// ``` /// ```
pub unsafe trait TransparentWrapper<Wrapped: ?Sized> { pub unsafe trait TransparentWrapper<Inner: ?Sized> {
/// Convert a reference to a wrapped type into a reference to the wrapper. /// Convert the inner type into the wrapper type.
///
/// This is a trait method so that you can write `MyType::wrap_ref(...)` in
/// your code. It is part of the safety contract for this trait that if you
/// implement `TransparentWrapper<_>` for your type you **must not** override
/// this method.
#[inline] #[inline]
fn wrap_ref(s: &Wrapped) -> &Self { fn wrap(s: Inner) -> Self
where
Self: Sized,
Inner: Sized,
{
// SAFETY: The unsafe contract requires that `Self` and `Inner` have
// identical representations.
unsafe { transmute_copy(&s) }
}
/// Convert a reference to the inner type into a reference to the wrapper
/// type.
#[inline]
fn wrap_ref(s: &Inner) -> &Self {
unsafe { unsafe {
assert!(size_of::<*const Wrapped>() == size_of::<*const Self>()); assert!(size_of::<*const Inner>() == size_of::<*const Self>());
// Using a pointer cast doesn't work here because rustc can't tell that the // A pointer cast does't work here because rustc can't tell that
// vtables match (if we lifted the ?Sized restriction, this would go away), // the vtables match (because of the `?Sized` restriction relaxation).
// and transmute doesn't work for the usual reasons it doesn't work inside // A `transmute` doesn't work because the sizes are unspecified.
// generic functions.
// //
// SAFETY: The unsafe contract requires that these have identical // SAFETY: The unsafe contract requires that these two have
// representations. Using this transmute_copy instead of transmute here is // identical representations.
// annoying, but is required as `Self` and `Wrapped` have unspecified let inner_ptr = s as *const Inner;
// sizes still. let wrapper_ptr: *const Self = transmute_copy(&inner_ptr);
let wrapped_ptr = s as *const Wrapped;
let wrapper_ptr: *const Self = transmute_copy(&wrapped_ptr);
&*wrapper_ptr &*wrapper_ptr
} }
} }
/// Convert a mut reference to a wrapped type into a mut reference to the /// Convert a mutable reference to the inner type into a mutable reference to
/// wrapper. /// the wrapper type.
///
/// This is a trait method so that you can write `MyType::wrap_mut(...)` in
/// your code. It is part of the safety contract for this trait that if you implement
/// `TransparentWrapper<_>` for your type you **must not** override this method.
#[inline] #[inline]
fn wrap_mut(s: &mut Wrapped) -> &mut Self { fn wrap_mut(s: &mut Inner) -> &mut Self {
unsafe { unsafe {
assert!(size_of::<*mut Wrapped>() == size_of::<*mut Self>()); assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
// Using a pointer cast doesn't work here because rustc can't tell that the // A pointer cast does't work here because rustc can't tell that
// vtables match (if we lifted the ?Sized restriction, this would go away), // the vtables match (because of the `?Sized` restriction relaxation).
// and transmute doesn't work for the usual reasons it doesn't work inside // A `transmute` doesn't work because the sizes are unspecified.
// generic functions.
// //
// SAFETY: The unsafe contract requires that these have identical // SAFETY: The unsafe contract requires that these two have
// representations. Using this transmute_copy instead of transmute here is // identical representations.
// annoying, but is required as `Self` and `Wrapped` have unspecified let inner_ptr = s as *mut Inner;
// sizes still. let wrapper_ptr: *mut Self = transmute_copy(&inner_ptr);
let wrapped_ptr = s as *mut Wrapped;
let wrapper_ptr: *mut Self = transmute_copy(&wrapped_ptr);
&mut *wrapper_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 unwrap(s: Self) -> Inner
where
Self: Sized,
Inner: Sized,
{
unsafe { transmute_copy(&s) }
}
/// Convert a reference to the wrapper type into a reference to the inner
/// type.
#[inline]
fn unwrap_ref(s: &Self) -> &Inner {
unsafe {
assert!(size_of::<*const Inner>() == size_of::<*const Self>());
// A pointer cast does'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_copy(&wrapper_ptr);
&*inner_ptr
}
}
/// Convert a mutable reference to the wrapper type into a mutable reference
/// to the inner type.
#[inline]
fn unwrap_mut(s: &mut Self) -> &mut Inner {
unsafe {
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
// A pointer cast does'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_copy(&wrapper_ptr);
&mut *inner_ptr
}
}
/// Convert a slice to the wrapped type into a slice to the inner type.
#[inline]
fn unwrap_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 unwrap_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> {} unsafe impl<T> TransparentWrapper<T> for core::num::Wrapping<T> {}

View File

@ -25,7 +25,8 @@ fn test_try_cast_slice() {
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
); );
// by taking one byte off the end, we're aligned but would have slop bytes for u32 // by taking one byte off the end, we're aligned but would have slop bytes for
// u32
let the_bytes_len_minus1 = the_bytes.len() - 1; let the_bytes_len_minus1 = the_bytes.len() - 1;
let slop_bytes = &the_bytes[..the_bytes_len_minus1]; let slop_bytes = &the_bytes[..the_bytes_len_minus1];
assert_eq!( assert_eq!(
@ -62,7 +63,8 @@ fn test_try_cast_slice_mut() {
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
); );
// by taking one byte off the end, we're aligned but would have slop bytes for u32 // by taking one byte off the end, we're aligned but would have slop bytes for
// u32
let the_bytes_len_minus1 = the_bytes.len() - 1; let the_bytes_len_minus1 = the_bytes.len() - 1;
let slop_bytes = &mut the_bytes[..the_bytes_len_minus1]; let slop_bytes = &mut the_bytes[..the_bytes_len_minus1];
assert_eq!( assert_eq!(
@ -92,7 +94,10 @@ fn test_types() {
#[test] #[test]
fn test_bytes_of() { fn test_bytes_of() {
assert_eq!(bytes_of(&0xaabbccdd_u32), &0xaabbccdd_u32.to_ne_bytes()); assert_eq!(bytes_of(&0xaabbccdd_u32), &0xaabbccdd_u32.to_ne_bytes());
assert_eq!(bytes_of_mut(&mut 0xaabbccdd_u32), &mut 0xaabbccdd_u32.to_ne_bytes()); assert_eq!(
bytes_of_mut(&mut 0xaabbccdd_u32),
&mut 0xaabbccdd_u32.to_ne_bytes()
);
let mut a = 0xaabbccdd_u32; let mut a = 0xaabbccdd_u32;
let a_addr = &a as *const _ as usize; let a_addr = &a as *const _ as usize;
// ensure addresses match. // ensure addresses match.
@ -105,9 +110,18 @@ fn test_try_from_bytes() {
let u32s = [0xaabbccdd, 0x11223344_u32]; let u32s = [0xaabbccdd, 0x11223344_u32];
let bytes = bytemuck::cast_slice::<u32, u8>(&u32s); let bytes = bytemuck::cast_slice::<u32, u8>(&u32s);
assert_eq!(try_from_bytes::<u32>(&bytes[..4]), Ok(&u32s[0])); assert_eq!(try_from_bytes::<u32>(&bytes[..4]), Ok(&u32s[0]));
assert_eq!(try_from_bytes::<u32>(&bytes[..5]), Err(PodCastError::SizeMismatch)); assert_eq!(
assert_eq!(try_from_bytes::<u32>(&bytes[..3]), Err(PodCastError::SizeMismatch)); try_from_bytes::<u32>(&bytes[..5]),
assert_eq!(try_from_bytes::<u32>(&bytes[1..5]), Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)); Err(PodCastError::SizeMismatch)
);
assert_eq!(
try_from_bytes::<u32>(&bytes[..3]),
Err(PodCastError::SizeMismatch)
);
assert_eq!(
try_from_bytes::<u32>(&bytes[1..5]),
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
);
} }
#[test] #[test]
@ -117,9 +131,18 @@ fn test_try_from_bytes_mut() {
let bytes = bytemuck::cast_slice_mut::<u32, u8>(&mut u32s); let bytes = bytemuck::cast_slice_mut::<u32, u8>(&mut u32s);
assert_eq!(try_from_bytes_mut::<u32>(&mut bytes[..4]), Ok(&mut abcd)); assert_eq!(try_from_bytes_mut::<u32>(&mut bytes[..4]), Ok(&mut abcd));
assert_eq!(try_from_bytes_mut::<u32>(&mut bytes[..4]), Ok(&mut abcd)); assert_eq!(try_from_bytes_mut::<u32>(&mut bytes[..4]), Ok(&mut abcd));
assert_eq!(try_from_bytes_mut::<u32>(&mut bytes[..5]), Err(PodCastError::SizeMismatch)); assert_eq!(
assert_eq!(try_from_bytes_mut::<u32>(&mut bytes[..3]), Err(PodCastError::SizeMismatch)); try_from_bytes_mut::<u32>(&mut bytes[..5]),
assert_eq!(try_from_bytes::<u32>(&mut bytes[1..5]), Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)); Err(PodCastError::SizeMismatch)
);
assert_eq!(
try_from_bytes_mut::<u32>(&mut bytes[..3]),
Err(PodCastError::SizeMismatch)
);
assert_eq!(
try_from_bytes::<u32>(&mut bytes[1..5]),
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
);
} }
#[test] #[test]
@ -136,7 +159,10 @@ fn test_from_bytes_mut() {
let a_addr = &a as *const _ as usize; let a_addr = &a as *const _ as usize;
let aligned_bytes = bytemuck::bytes_of_mut(&mut a); let aligned_bytes = bytemuck::bytes_of_mut(&mut a);
assert_eq!(*from_bytes_mut::<u32>(aligned_bytes), 0xaabbccdd_u32); assert_eq!(*from_bytes_mut::<u32>(aligned_bytes), 0xaabbccdd_u32);
assert_eq!(from_bytes_mut::<u32>(aligned_bytes) as *const u32 as usize, a_addr); assert_eq!(
from_bytes_mut::<u32>(aligned_bytes) as *const u32 as usize,
a_addr
);
} }
// like #[should_panic], but can be a part of another test, instead of requiring // like #[should_panic], but can be a part of another test, instead of requiring
@ -144,7 +170,10 @@ fn test_from_bytes_mut() {
macro_rules! should_panic { macro_rules! should_panic {
($ex:expr) => { ($ex:expr) => {
assert!( assert!(
std::panic::catch_unwind(|| { let _ = $ex; }).is_err(), std::panic::catch_unwind(|| {
let _ = $ex;
})
.is_err(),
concat!("should have panicked: `", stringify!($ex), "`") concat!("should have panicked: `", stringify!($ex), "`")
); );
}; };

View File

@ -1,7 +1,7 @@
#![cfg(feature = "derive")] #![cfg(feature = "derive")]
#![allow(dead_code)] #![allow(dead_code)]
use bytemuck::{Zeroable, Pod, TransparentWrapper}; use bytemuck::{Pod, TransparentWrapper, Zeroable};
#[derive(Copy, Clone, Pod, Zeroable)] #[derive(Copy, Clone, Pod, Zeroable)]
#[repr(C)] #[repr(C)]
@ -21,5 +21,5 @@ struct TransparentSingle {
#[transparent(u16)] #[transparent(u16)]
struct TransparentWithZeroSized { struct TransparentWithZeroSized {
a: u16, a: u16,
b: () b: (),
} }

64
tests/transparent.rs Normal file
View File

@ -0,0 +1,64 @@
// Currently this test doesn't actually check the output of the functions.
// It's only here for miri to check for any potential undefined behaviour.
// TODO: check function results
#[test]
fn test_transparent_wrapper() {
// An external type defined in a different crate.
#[derive(Copy, Clone, Default)]
struct Foreign(u8);
use bytemuck::TransparentWrapper;
#[derive(Copy, Clone)]
#[repr(transparent)]
struct Wrapper(Foreign);
unsafe impl TransparentWrapper<Foreign> for Wrapper {}
// Traits can be implemented on crate-local wrapper.
unsafe impl bytemuck::Zeroable for Wrapper {}
unsafe impl bytemuck::Pod for Wrapper {}
let _: u8 = bytemuck::cast(Wrapper::wrap(Foreign::default()));
let _: Foreign = Wrapper::unwrap(bytemuck::cast(u8::default()));
let _: &u8 = bytemuck::cast_ref(Wrapper::wrap_ref(&Foreign::default()));
let _: &Foreign = Wrapper::unwrap_ref(bytemuck::cast_ref(&u8::default()));
let _: &mut u8 =
bytemuck::cast_mut(Wrapper::wrap_mut(&mut Foreign::default()));
let _: &mut Foreign =
Wrapper::unwrap_mut(bytemuck::cast_mut(&mut u8::default()));
let _: &[u8] =
bytemuck::cast_slice(Wrapper::wrap_slice(&[Foreign::default()]));
let _: &[Foreign] =
Wrapper::unwrap_slice(bytemuck::cast_slice(&[u8::default()]));
let _: &mut [u8] =
bytemuck::cast_slice_mut(Wrapper::wrap_slice_mut(
&mut [Foreign::default()],
));
let _: &mut [Foreign] =
Wrapper::unwrap_slice_mut(bytemuck::cast_slice_mut(&mut [u8::default()]));
let _: &[u8] = bytemuck::bytes_of(Wrapper::wrap_ref(&Foreign::default()));
let _: &Foreign = Wrapper::unwrap_ref(bytemuck::from_bytes(&[u8::default()]));
let _: &mut [u8] =
bytemuck::bytes_of_mut(Wrapper::wrap_mut(&mut Foreign::default()));
let _: &mut Foreign =
Wrapper::unwrap_mut(bytemuck::from_bytes_mut(&mut [u8::default()]));
// not sure if this is the right usage
let _ =
bytemuck::pod_align_to::<_, u8>(Wrapper::wrap_slice(&[Foreign::default()]));
// counterpart?
// not sure if this is the right usage
let _ = bytemuck::pod_align_to_mut::<_, u8>(Wrapper::wrap_slice_mut(&mut [
Foreign::default(),
]));
// counterpart?
}