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 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..6fb53bc 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -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`: +/// 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 +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 { - /// 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 { + 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 TransparentWrapper for core::num::Wrapping {} 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: (), +} 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? +}