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?
+}