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::() {