mirror of
https://github.com/Lokathor/bytemuck.git
synced 2024-11-23 23:32:24 +00:00
[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:
parent
08a4b8fbc2
commit
30a96066fa
@ -12,5 +12,5 @@ use_small_heuristics = "Max"
|
||||
|
||||
# Unstable
|
||||
format_code_in_doc_comments = true
|
||||
merge_imports = true
|
||||
imports_granularity = "Crate"
|
||||
wrap_comments = true
|
||||
|
@ -85,8 +85,8 @@ pub unsafe trait Contiguous: Copy + 'static {
|
||||
/// `#[repr(Int)]` or `#[repr(C)]` attribute, (if it does not, it is
|
||||
/// *unsound* to implement `Contiguous`!).
|
||||
///
|
||||
/// - For `#[repr(Int)]`, use the listed `Int`. e.g. `#[repr(u8)]` should
|
||||
/// use `type Int = u8`.
|
||||
/// - For `#[repr(Int)]`, use the listed `Int`. e.g. `#[repr(u8)]` should use
|
||||
/// `type Int = u8`.
|
||||
///
|
||||
/// - 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`
|
||||
|
@ -25,7 +25,9 @@
|
||||
/// # use bytemuck::offset_of;
|
||||
/// // enums can't derive default, and for this example we don't pick one
|
||||
/// enum MyExampleEnum {
|
||||
/// A, B, C,
|
||||
/// A,
|
||||
/// B,
|
||||
/// C,
|
||||
/// }
|
||||
///
|
||||
/// // 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
|
||||
///
|
||||
/// <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.
|
||||
/// Previous versions of
|
||||
/// <strong>Warning:</strong> This is only true for versions of bytemuck >
|
||||
/// 1.4.0. Previous versions of
|
||||
/// <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,
|
||||
/// which can lead to unsoundness.
|
||||
/// will only emit a warning when used on the field of a packed struct in safe
|
||||
/// code, which can lead to unsoundness.
|
||||
/// </p>
|
||||
///
|
||||
/// For example, the following will fail to compile:
|
||||
@ -91,7 +93,8 @@
|
||||
/// ```compile_fail
|
||||
/// # #[repr(C, packed)] #[derive(Default)] struct Example { field: u32 }
|
||||
/// // Still doesn't compile:
|
||||
/// #[allow(safe_packed_borrows)] {
|
||||
/// #[allow(safe_packed_borrows)]
|
||||
/// {
|
||||
/// let _offset = bytemuck::offset_of!(Example, field);
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -1,38 +1,42 @@
|
||||
use super::*;
|
||||
|
||||
/// A trait which indicates that a type is a `repr(transparent)` wrapper around
|
||||
/// the `Wrapped` value.
|
||||
/// A trait which indicates that a type is a `#[repr(transparent)]` wrapper
|
||||
/// around the `Inner` value.
|
||||
///
|
||||
/// This allows safely creating references to `T` from those to the `Wrapped`
|
||||
/// type, using the `wrap_ref` and `wrap_mut` functions.
|
||||
/// 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 `unwrap_{}` functions do the inverse conversion
|
||||
/// from the wrapper type to the inner type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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
|
||||
/// either means that it must be a `#[repr(transparent)]` struct which
|
||||
/// contains a either a field of type `Wrapped` (or a field of some other
|
||||
/// transparent wrapper for `Wrapped`) as the only non-ZST field.
|
||||
/// 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 `Wrapped` field must be trivially
|
||||
/// 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
|
||||
/// `Wrapped`.
|
||||
/// `Inner`.
|
||||
/// - Note: this is currently guaranteed by `repr(transparent)`, but there
|
||||
/// have been discussions of lifting it, so it's stated here explicitly.
|
||||
///
|
||||
/// 4. The `wrap_ref` and `wrap_mut` functions on `TransparentWrapper` may not
|
||||
/// be overridden.
|
||||
/// 4. All functions on
|
||||
/// `TransparentWrapper` **may not** be overridden.
|
||||
///
|
||||
/// ## 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 --
|
||||
/// 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
|
||||
/// `T::cast_ref(any_instance_of_u)`.
|
||||
///
|
||||
@ -55,13 +59,13 @@ use super::*;
|
||||
///
|
||||
/// // interpret a reference to &SomeStruct as a &MyWrapper
|
||||
/// let thing = SomeStruct::default();
|
||||
/// let wrapped_ref: &MyWrapper = MyWrapper::wrap_ref(&thing);
|
||||
/// let inner_ref: &MyWrapper = MyWrapper::wrap_ref(&thing);
|
||||
///
|
||||
/// // Works with &mut too.
|
||||
/// 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
|
||||
@ -80,56 +84,166 @@ use super::*;
|
||||
/// let mut buf = [1, 2, 3u8];
|
||||
/// let sm = Slice::wrap_mut(&mut buf);
|
||||
/// ```
|
||||
pub unsafe trait TransparentWrapper<Wrapped: ?Sized> {
|
||||
/// Convert a reference to a wrapped type into a reference to the wrapper.
|
||||
///
|
||||
/// 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.
|
||||
pub unsafe trait TransparentWrapper<Inner: ?Sized> {
|
||||
/// Convert the inner type into the wrapper type.
|
||||
#[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 {
|
||||
assert!(size_of::<*const Wrapped>() == size_of::<*const Self>());
|
||||
// Using a pointer cast doesn't work here because rustc can't tell that the
|
||||
// vtables match (if we lifted the ?Sized restriction, this would go away),
|
||||
// and transmute doesn't work for the usual reasons it doesn't work inside
|
||||
// generic functions.
|
||||
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 have identical
|
||||
// representations. Using this transmute_copy instead of transmute here is
|
||||
// annoying, but is required as `Self` and `Wrapped` have unspecified
|
||||
// sizes still.
|
||||
let wrapped_ptr = s as *const Wrapped;
|
||||
let wrapper_ptr: *const Self = transmute_copy(&wrapped_ptr);
|
||||
// SAFETY: The unsafe contract requires that these two have
|
||||
// identical representations.
|
||||
let inner_ptr = s as *const Inner;
|
||||
let wrapper_ptr: *const Self = transmute_copy(&inner_ptr);
|
||||
&*wrapper_ptr
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a mut reference to a wrapped type into a mut reference to the
|
||||
/// wrapper.
|
||||
///
|
||||
/// 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.
|
||||
/// Convert a mutable reference to the inner type into a mutable reference to
|
||||
/// the wrapper type.
|
||||
#[inline]
|
||||
fn wrap_mut(s: &mut Wrapped) -> &mut Self {
|
||||
fn wrap_mut(s: &mut Inner) -> &mut Self {
|
||||
unsafe {
|
||||
assert!(size_of::<*mut Wrapped>() == size_of::<*mut Self>());
|
||||
// Using a pointer cast doesn't work here because rustc can't tell that the
|
||||
// vtables match (if we lifted the ?Sized restriction, this would go away),
|
||||
// and transmute doesn't work for the usual reasons it doesn't work inside
|
||||
// generic functions.
|
||||
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 have identical
|
||||
// representations. Using this transmute_copy instead of transmute here is
|
||||
// annoying, but is required as `Self` and `Wrapped` have unspecified
|
||||
// sizes still.
|
||||
let wrapped_ptr = s as *mut Wrapped;
|
||||
let wrapper_ptr: *mut Self = transmute_copy(&wrapped_ptr);
|
||||
// SAFETY: The unsafe contract requires that these two have
|
||||
// identical representations.
|
||||
let inner_ptr = s as *mut Inner;
|
||||
let wrapper_ptr: *mut Self = transmute_copy(&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 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> {}
|
||||
|
@ -25,7 +25,8 @@ fn test_try_cast_slice() {
|
||||
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 slop_bytes = &the_bytes[..the_bytes_len_minus1];
|
||||
assert_eq!(
|
||||
@ -62,7 +63,8 @@ fn test_try_cast_slice_mut() {
|
||||
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 slop_bytes = &mut the_bytes[..the_bytes_len_minus1];
|
||||
assert_eq!(
|
||||
@ -92,7 +94,10 @@ fn test_types() {
|
||||
#[test]
|
||||
fn test_bytes_of() {
|
||||
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 a_addr = &a as *const _ as usize;
|
||||
// ensure addresses match.
|
||||
@ -105,9 +110,18 @@ fn test_try_from_bytes() {
|
||||
let u32s = [0xaabbccdd, 0x11223344_u32];
|
||||
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[..5]), 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));
|
||||
assert_eq!(
|
||||
try_from_bytes::<u32>(&bytes[..5]),
|
||||
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]
|
||||
@ -117,9 +131,18 @@ fn test_try_from_bytes_mut() {
|
||||
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[..5]), 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));
|
||||
assert_eq!(
|
||||
try_from_bytes_mut::<u32>(&mut bytes[..5]),
|
||||
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]
|
||||
@ -136,7 +159,10 @@ fn test_from_bytes_mut() {
|
||||
let a_addr = &a as *const _ as usize;
|
||||
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) 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
|
||||
@ -144,7 +170,10 @@ fn test_from_bytes_mut() {
|
||||
macro_rules! should_panic {
|
||||
($ex:expr) => {
|
||||
assert!(
|
||||
std::panic::catch_unwind(|| { let _ = $ex; }).is_err(),
|
||||
std::panic::catch_unwind(|| {
|
||||
let _ = $ex;
|
||||
})
|
||||
.is_err(),
|
||||
concat!("should have panicked: `", stringify!($ex), "`")
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![cfg(feature = "derive")]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use bytemuck::{Zeroable, Pod, TransparentWrapper};
|
||||
use bytemuck::{Pod, TransparentWrapper, Zeroable};
|
||||
|
||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
@ -21,5 +21,5 @@ struct TransparentSingle {
|
||||
#[transparent(u16)]
|
||||
struct TransparentWithZeroSized {
|
||||
a: u16,
|
||||
b: ()
|
||||
b: (),
|
||||
}
|
64
tests/transparent.rs
Normal file
64
tests/transparent.rs
Normal 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?
|
||||
}
|
Loading…
Reference in New Issue
Block a user