From 6769e51de15850cab2630086f3cfe3448fd84271 Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Sun, 21 Mar 2021 21:03:29 +0100 Subject: [PATCH 1/8] update rustfmt.toml replace `merge_imports = true` (deprecated) with `imports_granularity = "Crate"` --- rustfmt.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustfmt.toml b/rustfmt.toml index f214385..689ceb1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -12,5 +12,5 @@ use_small_heuristics = "Max" # Unstable format_code_in_doc_comments = true -merge_imports = true +imports_granularity = "Crate" wrap_comments = true From 47a21ffe7bf3227169a48c9d60cf3c91573dee78 Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Sun, 21 Mar 2021 21:09:28 +0100 Subject: [PATCH 2/8] run `cargo +nightly fmt` --- src/contiguous.rs | 4 +-- src/offset_of.rs | 15 +++++++----- src/transparent.rs | 21 ++++++++-------- tests/cast_slice_tests.rs | 51 ++++++++++++++++++++++++++++++--------- tests/derive.rs | 6 ++--- 5 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/contiguous.rs b/src/contiguous.rs index 30709a7..b60f4a4 100644 --- a/src/contiguous.rs +++ b/src/contiguous.rs @@ -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` diff --git a/src/offset_of.rs b/src/offset_of.rs index 604379a..7e8aedf 100644 --- a/src/offset_of.rs +++ b/src/offset_of.rs @@ -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 /// ///

-/// Warning: This is only true for versions of bytemuck > 1.4.0. -/// Previous versionsĀ of +/// Warning: This is only true for versions of bytemuck > +/// 1.4.0. Previous versionsĀ of /// bytemuck::offset_of! -/// 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. ///

/// /// 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); /// } /// ``` diff --git a/src/transparent.rs b/src/transparent.rs index fa6d479..aaddf25 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -91,10 +91,10 @@ pub unsafe trait TransparentWrapper { fn wrap_ref(s: &Wrapped) -> &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. + // 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. // // SAFETY: The unsafe contract requires that these have identical // representations. Using this transmute_copy instead of transmute here is @@ -110,16 +110,17 @@ pub unsafe trait TransparentWrapper { /// 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. + /// 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] fn wrap_mut(s: &mut Wrapped) -> &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. + // 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. // // SAFETY: The unsafe contract requires that these have identical // representations. Using this transmute_copy instead of transmute here is diff --git a/tests/cast_slice_tests.rs b/tests/cast_slice_tests.rs index 9eb08c5..515a628 100644 --- a/tests/cast_slice_tests.rs +++ b/tests/cast_slice_tests.rs @@ -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::(&u32s); assert_eq!(try_from_bytes::(&bytes[..4]), Ok(&u32s[0])); - assert_eq!(try_from_bytes::(&bytes[..5]), Err(PodCastError::SizeMismatch)); - assert_eq!(try_from_bytes::(&bytes[..3]), Err(PodCastError::SizeMismatch)); - assert_eq!(try_from_bytes::(&bytes[1..5]), Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)); + assert_eq!( + try_from_bytes::(&bytes[..5]), + Err(PodCastError::SizeMismatch) + ); + assert_eq!( + try_from_bytes::(&bytes[..3]), + Err(PodCastError::SizeMismatch) + ); + assert_eq!( + try_from_bytes::(&bytes[1..5]), + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + ); } #[test] @@ -117,9 +131,18 @@ fn test_try_from_bytes_mut() { let bytes = bytemuck::cast_slice_mut::(&mut u32s); assert_eq!(try_from_bytes_mut::(&mut bytes[..4]), Ok(&mut abcd)); assert_eq!(try_from_bytes_mut::(&mut bytes[..4]), Ok(&mut abcd)); - assert_eq!(try_from_bytes_mut::(&mut bytes[..5]), Err(PodCastError::SizeMismatch)); - assert_eq!(try_from_bytes_mut::(&mut bytes[..3]), Err(PodCastError::SizeMismatch)); - assert_eq!(try_from_bytes::(&mut bytes[1..5]), Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)); + assert_eq!( + try_from_bytes_mut::(&mut bytes[..5]), + Err(PodCastError::SizeMismatch) + ); + assert_eq!( + try_from_bytes_mut::(&mut bytes[..3]), + Err(PodCastError::SizeMismatch) + ); + assert_eq!( + try_from_bytes::(&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::(aligned_bytes), 0xaabbccdd_u32); - assert_eq!(from_bytes_mut::(aligned_bytes) as *const u32 as usize, a_addr); + assert_eq!( + from_bytes_mut::(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), "`") ); }; diff --git a/tests/derive.rs b/tests/derive.rs index 1e1deeb..2524e6d 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -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: () -} \ No newline at end of file + b: (), +} From 6fa9a3b55898ed231c36b2022783797681f1a3b0 Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Tue, 23 Mar 2021 22:05:41 +0100 Subject: [PATCH 3/8] 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` --- src/transparent.rs | 100 ++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/src/transparent.rs b/src/transparent.rs index aaddf25..6d74fd3 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -1,38 +1,41 @@ use super::*; /// A trait which indicates that a type is a `repr(transparent)` wrapper around -/// the `Wrapped` value. +/// 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 transmuting between the `Inner` type and the +/// `TransparentWrapper` type. +/// Functions like `wrap_{}` convert from the inner +/// type to the wrapper type. /// /// # Safety /// /// The safety contract of `TransparentWrapper` is relatively simple: /// -/// For a given `Wrapper` which implements `TransparentWrapper`: +/// For a given `Wrapper` which implements `TransparentWrapper`: /// -/// 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 for T` means anybody can call /// `T::cast_ref(any_instance_of_u)`. /// @@ -55,13 +58,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,54 +83,41 @@ use super::*; /// let mut buf = [1, 2, 3u8]; /// let sm = Slice::wrap_mut(&mut buf); /// ``` -pub unsafe trait TransparentWrapper { - /// 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 { + /// Convert the inner type into the wrapper type. #[inline] - fn wrap_ref(s: &Wrapped) -> &Self { + /// 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 } } From 9e353ed9b34ba1da707454e0f42db121c1f8a6c3 Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Tue, 23 Mar 2021 22:08:48 +0100 Subject: [PATCH 4/8] 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]` --- src/transparent.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/transparent.rs b/src/transparent.rs index 6d74fd3..ccc49f4 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -86,6 +86,16 @@ use super::*; pub unsafe trait TransparentWrapper { /// 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_copy(&s) } + } + /// Convert a reference to the inner type into a reference to the wrapper /// type. #[inline] @@ -121,6 +131,39 @@ pub unsafe trait TransparentWrapper { &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()) + } + } } unsafe impl TransparentWrapper for core::num::Wrapping {} From 9aaed8d4bdc334ca7326b4ffd50d05822eaf13f1 Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Tue, 23 Mar 2021 22:13:22 +0100 Subject: [PATCH 5/8] 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]` --- src/transparent.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/transparent.rs b/src/transparent.rs index ccc49f4..e950473 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -6,7 +6,8 @@ use super::*; /// This allows safely transmuting between the `Inner` type and the /// `TransparentWrapper` type. /// Functions like `wrap_{}` convert from the inner -/// type to the wrapper type. +/// type to the wrapper type and `unwrap_{}` functions do the inverse conversion +/// from the wrapper type to the inner type. /// /// # Safety /// @@ -164,6 +165,85 @@ pub unsafe trait TransparentWrapper { 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(self) -> Inner + where + Self: Sized, + Inner: Sized, + { + unsafe { transmute_copy(&self) } + } + + /// Convert a reference to the wrapper type into a reference to the inner + /// type. + #[inline] + fn unwrap_ref(&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 = self 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(&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 = self 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 TransparentWrapper for core::num::Wrapping {} From 665737ba875e69d1a8f42648dd5544df25415538 Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Tue, 23 Mar 2021 22:17:34 +0100 Subject: [PATCH 6/8] 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. --- tests/transparent.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/transparent.rs diff --git a/tests/transparent.rs b/tests/transparent.rs new file mode 100644 index 0000000..f0f9da8 --- /dev/null +++ b/tests/transparent.rs @@ -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 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? +} From aa77a3a3a506b98d918f846b93ae0d8047fb51bb Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Thu, 25 Mar 2021 17:53:06 +0100 Subject: [PATCH 7/8] small `TransparentWrapper` doc adjustments --- src/transparent.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/transparent.rs b/src/transparent.rs index e950473..4755ff8 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -1,9 +1,9 @@ use super::*; -/// A trait which indicates that a type is a `repr(transparent)` wrapper around -/// the `Inner` value. +/// A trait which indicates that a type is a `#[repr(transparent)]` wrapper +/// around the `Inner` value. /// -/// This allows safely transmuting between the `Inner` type and the +/// 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 e4e4f4a531a761986cfba751b67ee989b3fec42a Mon Sep 17 00:00:00 2001 From: Luis Wirth Date: Thu, 25 Mar 2021 17:56:09 +0100 Subject: [PATCH 8/8] 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)` --- src/transparent.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/transparent.rs b/src/transparent.rs index 4755ff8..6fb53bc 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -168,18 +168,18 @@ pub unsafe trait TransparentWrapper { /// Convert the wrapper type into the inner type. #[inline] - fn unwrap(self) -> Inner + fn unwrap(s: Self) -> Inner where Self: Sized, Inner: Sized, { - unsafe { transmute_copy(&self) } + unsafe { transmute_copy(&s) } } /// Convert a reference to the wrapper type into a reference to the inner /// type. #[inline] - fn unwrap_ref(&self) -> &Inner { + 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 @@ -188,7 +188,7 @@ pub unsafe trait TransparentWrapper { // // SAFETY: The unsafe contract requires that these two have // identical representations. - let wrapper_ptr = self as *const Self; + let wrapper_ptr = s as *const Self; let inner_ptr: *const Inner = transmute_copy(&wrapper_ptr); &*inner_ptr } @@ -197,7 +197,7 @@ pub unsafe trait TransparentWrapper { /// Convert a mutable reference to the wrapper type into a mutable reference /// to the inner type. #[inline] - fn unwrap_mut(&mut self) -> &mut Inner { + 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 @@ -206,7 +206,7 @@ pub unsafe trait TransparentWrapper { // // SAFETY: The unsafe contract requires that these two have // identical representations. - let wrapper_ptr = self as *mut Self; + let wrapper_ptr = s as *mut Self; let inner_ptr: *mut Inner = transmute_copy(&wrapper_ptr); &mut *inner_ptr }