From 5eecd333183762078be87b7b499dd80cd83bf45a Mon Sep 17 00:00:00 2001 From: zachs18 <8355914+zachs18@users.noreply.github.com> Date: Sun, 11 Aug 2024 07:59:06 +0000 Subject: [PATCH] Make must_cast by-value and by-shared-ref functions const (#261) * Make must_cast by-value and by-shared-ref functions const (but not by-mut-ref) * Add comment for transmute! macro new arm, and update Cargo.toml comment for must_cast MSRV. --- Cargo.toml | 2 +- src/lib.rs | 11 +++++++++++ src/must.rs | 8 ++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ffa457b..8b82ddb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ min_const_generics = [] # MSRV 1.51: support arrays via min_const_generics wasm_simd = [] # MSRV 1.54.0: support wasm simd types aarch64_simd = [] # MSRV 1.59.0: support aarch64 simd types -must_cast = [] # MSRV 1.57.0: support the `must` module. +must_cast = [] # MSRV 1.64.0: support the `must` module. const_zeroed = [] # MSRV 1.75.0: support const `zeroed()` diff --git a/src/lib.rs b/src/lib.rs index dfb8ae8..cafab3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,6 +123,17 @@ macro_rules! transmute { ($val:expr) => { ::core::mem::transmute_copy(&::core::mem::ManuallyDrop::new($val)) }; + // This arm is for use in const contexts, where the borrow required to use transmute_copy poses an issue + // since the compiler hedges that the type being borrowed could have interior mutability. + ($srcty:ty; $dstty:ty; $val:expr) => { + { + union Transmute { + src: ::core::mem::ManuallyDrop, + dst: ::core::mem::ManuallyDrop, + } + ::core::mem::ManuallyDrop::into_inner(Transmute::<$srcty, $dstty> { src: ::core::mem::ManuallyDrop::new($val) }.dst) + } + } } /// A macro to implement marker traits for various simd types. diff --git a/src/must.rs b/src/must.rs index 4c8c613..c937c06 100644 --- a/src/must.rs +++ b/src/must.rs @@ -38,9 +38,9 @@ impl Cast { /// let bytes : [u8; 3] = bytemuck::must_cast(12_u16); /// ``` #[inline] -pub fn must_cast(a: A) -> B { +pub const fn must_cast(a: A) -> B { let _ = Cast::::ASSERT_SIZE_EQUAL; - unsafe { transmute!(a) } + unsafe { transmute!(A; B; a) } } /// Convert `&A` into `&B` if infalliable, or fail to compile. @@ -64,7 +64,7 @@ pub fn must_cast(a: A) -> B { /// let bytes : &u16 = bytemuck::must_cast_ref(&[1u8, 2u8]); /// ``` #[inline] -pub fn must_cast_ref(a: &A) -> &B { +pub const fn must_cast_ref(a: &A) -> &B { let _ = Cast::::ASSERT_SIZE_EQUAL; let _ = Cast::::ASSERT_ALIGN_GREATER_THAN_EQUAL; unsafe { &*(a as *const A as *const B) } @@ -143,7 +143,7 @@ pub fn must_cast_mut< /// let zsts: &[()] = bytemuck::must_cast_slice(bytes); /// ``` #[inline] -pub fn must_cast_slice(a: &[A]) -> &[B] { +pub const fn must_cast_slice(a: &[A]) -> &[B] { let _ = Cast::::ASSERT_SIZE_MULTIPLE_OF_OR_INPUT_ZST; let _ = Cast::::ASSERT_ALIGN_GREATER_THAN_EQUAL; let new_len = if size_of::() == size_of::() {