Skip to content

Commit 4705197

Browse files
committed
conditionally constify some functions, and implement traits on types that don't require nightly anymore
1 parent 9bf993b commit 4705197

File tree

6 files changed

+151
-87
lines changed

6 files changed

+151
-87
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ min_const_generics = [] # MSRV 1.51: support arrays via min_const_generics
3737

3838
wasm_simd = [] # MSRV 1.54.0: support wasm simd types
3939
aarch64_simd = [] # MSRV 1.59.0: support aarch64 simd types
40+
avx512_simd = [] # MSRV 1.72.0: support avx512 simd types
4041

4142
must_cast = [] # MSRV 1.64.0: support the `must` module.
43+
must_cast_extra = ["must_cast"] # MSRV 1.83.0: support mutable references in const
4244

4345
# Adds `TransparentWrapper` impls for stdlib types newer than bytemuck's base MSRV.
4446
# Current MSRV 1.74.0: `core::num::Saturating`.
@@ -62,12 +64,14 @@ track_caller = []
6264
latest_stable_rust = [
6365
# Keep this list sorted.
6466
"aarch64_simd",
67+
"avx512_simd",
6568
"align_offset",
6669
"alloc_uninit",
6770
"const_zeroed",
6871
"derive",
6972
"min_const_generics",
7073
"must_cast",
74+
"must_cast_extra",
7175
"track_caller",
7276
"wasm_simd",
7377
"zeroable_atomics",

changelog.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# `bytemuck` changelog
22

3+
## Unreleased
4+
5+
* Implement `Pod` and `Zeroable` for `__m512`, `__m512d` and `__m512i` without nightly.
6+
Requires Rust 1.70, and is gated through the `avx512_simd` cargo feature.
7+
8+
* Allow the use of `must_cast_mut` and `must_cast_slice_mut` in const contexts.
9+
Requires Rust 1.83, and is gated through the `must_cast_extra` cargo feature.
10+
11+
* internal: introduced the `maybe_const_fn` macro that allows defining some function
12+
to be const depending upon some `cfg` predicate.
13+
314
## 1.20
415

516
* New functions to allocate zeroed `Arc` and `Rc`. Requires Rust 1.82

src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,25 @@ macro_rules! impl_unsafe_marker_for_simd {
154154
};
155155
}
156156

157+
/// A macro for conditionally const-ifying a function.
158+
/// #[allow(unused)] because currently it is only used with the `must_cast` feature.
159+
#[allow(unused)]
160+
macro_rules! maybe_const_fn {
161+
(
162+
#[cfg($cfg_predicate:meta)]
163+
$(#[$attr:meta])*
164+
$vis:vis $(unsafe $($unsafe:lifetime)?)? fn $name:ident $($rest:tt)*
165+
) => {
166+
#[cfg($cfg_predicate)]
167+
$(#[$attr])*
168+
$vis const $(unsafe $($unsafe)?)? fn $name $($rest)*
169+
170+
#[cfg(not($cfg_predicate))]
171+
$(#[$attr])*
172+
$vis $(unsafe $($unsafe)?)? fn $name $($rest)*
173+
};
174+
}
175+
157176
#[cfg(feature = "extern_crate_std")]
158177
extern crate std;
159178

src/must.rs

Lines changed: 85 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -70,36 +70,39 @@ pub const fn must_cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> &B {
7070
unsafe { &*(a as *const A as *const B) }
7171
}
7272

73-
/// Convert a `&mut A` into `&mut B` if infalliable, or fail to compile.
74-
///
75-
/// As [`must_cast_ref`], but `mut`.
76-
///
77-
/// ## Examples
78-
/// ```
79-
/// let mut i = 12_u16;
80-
/// // compiles:
81-
/// let bytes: &mut [u8; 2] = bytemuck::must_cast_mut(&mut i);
82-
/// ```
83-
/// ```compile_fail,E0080
84-
/// # let mut bytes: &mut [u8; 2] = &mut [1, 2];
85-
/// // fails to compile (alignment requirements increased):
86-
/// let i : &mut u16 = bytemuck::must_cast_mut(bytes);
87-
/// ```
88-
/// ```compile_fail,E0080
89-
/// # let mut i = 12_u16;
90-
/// // fails to compile (size mismatch):
91-
/// let bytes : &mut [u8; 3] = bytemuck::must_cast_mut(&mut i);
92-
/// ```
93-
#[inline]
94-
pub fn must_cast_mut<
95-
A: NoUninit + AnyBitPattern,
96-
B: NoUninit + AnyBitPattern,
97-
>(
98-
a: &mut A,
99-
) -> &mut B {
100-
let _ = Cast::<A, B>::ASSERT_SIZE_EQUAL;
101-
let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
102-
unsafe { &mut *(a as *mut A as *mut B) }
73+
maybe_const_fn! {
74+
#[cfg(feature = "must_cast_extra")]
75+
/// Convert a `&mut A` into `&mut B` if infalliable, or fail to compile.
76+
///
77+
/// As [`must_cast_ref`], but `mut`.
78+
///
79+
/// ## Examples
80+
/// ```
81+
/// let mut i = 12_u16;
82+
/// // compiles:
83+
/// let bytes: &mut [u8; 2] = bytemuck::must_cast_mut(&mut i);
84+
/// ```
85+
/// ```compile_fail,E0080
86+
/// # let mut bytes: &mut [u8; 2] = &mut [1, 2];
87+
/// // fails to compile (alignment requirements increased):
88+
/// let i : &mut u16 = bytemuck::must_cast_mut(bytes);
89+
/// ```
90+
/// ```compile_fail,E0080
91+
/// # let mut i = 12_u16;
92+
/// // fails to compile (size mismatch):
93+
/// let bytes : &mut [u8; 3] = bytemuck::must_cast_mut(&mut i);
94+
/// ```
95+
#[inline]
96+
pub fn must_cast_mut<
97+
A: NoUninit + AnyBitPattern,
98+
B: NoUninit + AnyBitPattern,
99+
>(
100+
a: &mut A,
101+
) -> &mut B {
102+
let _ = Cast::<A, B>::ASSERT_SIZE_EQUAL;
103+
let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
104+
unsafe { &mut *(a as *mut A as *mut B) }
105+
}
103106
}
104107

105108
/// Convert `&[A]` into `&[B]` (possibly with a change in length) if
@@ -154,53 +157,56 @@ pub const fn must_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B] {
154157
unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) }
155158
}
156159

157-
/// Convert `&mut [A]` into `&mut [B]` (possibly with a change in length) if
158-
/// infalliable, or fail to compile.
159-
///
160-
/// As [`must_cast_slice`], but `&mut`.
161-
///
162-
/// ## Examples
163-
/// ```
164-
/// let mut indicies = [1, 2, 3];
165-
/// let indicies: &mut [u16] = &mut indicies;
166-
/// // compiles:
167-
/// let bytes: &mut [u8] = bytemuck::must_cast_slice_mut(indicies);
168-
/// ```
169-
/// ```
170-
/// let zsts: &mut [()] = &mut [(), (), ()];
171-
/// // compiles:
172-
/// let bytes: &mut [u8] = bytemuck::must_cast_slice_mut(zsts);
173-
/// ```
174-
/// ```compile_fail,E0080
175-
/// # let mut bytes = [1, 0, 2, 0, 3, 0];
176-
/// # let bytes : &mut [u8] = &mut bytes[..];
177-
/// // fails to compile (bytes.len() might not be a multiple of 2):
178-
/// let byte_pairs : &mut [[u8; 2]] = bytemuck::must_cast_slice_mut(bytes);
179-
/// ```
180-
/// ```compile_fail,E0080
181-
/// # let mut byte_pairs = [[1, 0], [2, 0], [3, 0]];
182-
/// # let byte_pairs : &mut [[u8; 2]] = &mut byte_pairs[..];
183-
/// // fails to compile (alignment requirements increased):
184-
/// let indicies : &mut [u16] = bytemuck::must_cast_slice_mut(byte_pairs);
185-
/// ```
186-
/// ```compile_fail,E0080
187-
/// let bytes: &mut [u8] = &mut [];
188-
/// // fails to compile: (bytes.len() might not be 0)
189-
/// let zsts: &mut [()] = bytemuck::must_cast_slice_mut(bytes);
190-
/// ```
191-
#[inline]
192-
pub fn must_cast_slice_mut<
193-
A: NoUninit + AnyBitPattern,
194-
B: NoUninit + AnyBitPattern,
195-
>(
196-
a: &mut [A],
197-
) -> &mut [B] {
198-
let _ = Cast::<A, B>::ASSERT_SIZE_MULTIPLE_OF_OR_INPUT_ZST;
199-
let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
200-
let new_len = if size_of::<A>() == size_of::<B>() {
201-
a.len()
202-
} else {
203-
a.len() * (size_of::<A>() / size_of::<B>())
204-
};
205-
unsafe { core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) }
160+
maybe_const_fn! {
161+
#[cfg(feature = "must_cast_extra")]
162+
/// Convert `&mut [A]` into `&mut [B]` (possibly with a change in length) if
163+
/// infalliable, or fail to compile.
164+
///
165+
/// As [`must_cast_slice`], but `&mut`.
166+
///
167+
/// ## Examples
168+
/// ```
169+
/// let mut indicies = [1, 2, 3];
170+
/// let indicies: &mut [u16] = &mut indicies;
171+
/// // compiles:
172+
/// let bytes: &mut [u8] = bytemuck::must_cast_slice_mut(indicies);
173+
/// ```
174+
/// ```
175+
/// let zsts: &mut [()] = &mut [(), (), ()];
176+
/// // compiles:
177+
/// let bytes: &mut [u8] = bytemuck::must_cast_slice_mut(zsts);
178+
/// ```
179+
/// ```compile_fail,E0080
180+
/// # let mut bytes = [1, 0, 2, 0, 3, 0];
181+
/// # let bytes : &mut [u8] = &mut bytes[..];
182+
/// // fails to compile (bytes.len() might not be a multiple of 2):
183+
/// let byte_pairs : &mut [[u8; 2]] = bytemuck::must_cast_slice_mut(bytes);
184+
/// ```
185+
/// ```compile_fail,E0080
186+
/// # let mut byte_pairs = [[1, 0], [2, 0], [3, 0]];
187+
/// # let byte_pairs : &mut [[u8; 2]] = &mut byte_pairs[..];
188+
/// // fails to compile (alignment requirements increased):
189+
/// let indicies : &mut [u16] = bytemuck::must_cast_slice_mut(byte_pairs);
190+
/// ```
191+
/// ```compile_fail,E0080
192+
/// let bytes: &mut [u8] = &mut [];
193+
/// // fails to compile: (bytes.len() might not be 0)
194+
/// let zsts: &mut [()] = bytemuck::must_cast_slice_mut(bytes);
195+
/// ```
196+
#[inline]
197+
pub fn must_cast_slice_mut<
198+
A: NoUninit + AnyBitPattern,
199+
B: NoUninit + AnyBitPattern,
200+
>(
201+
a: &mut [A],
202+
) -> &mut [B] {
203+
let _ = Cast::<A, B>::ASSERT_SIZE_MULTIPLE_OF_OR_INPUT_ZST;
204+
let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
205+
let new_len = if size_of::<A>() == size_of::<B>() {
206+
a.len()
207+
} else {
208+
a.len() * (size_of::<A>() / size_of::<B>())
209+
};
210+
unsafe { core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) }
211+
}
206212
}

src/pod.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,30 @@ where
152152
{
153153
}
154154

155+
impl_unsafe_marker_for_simd!(
156+
#[cfg(all(target_arch = "x86", any(feature = "nightly_stdsimd", feature = "avx512_simd")))]
157+
unsafe impl Pod for x86::{
158+
__m512, __m512d, __m512i
159+
}
160+
);
161+
162+
impl_unsafe_marker_for_simd!(
163+
#[cfg(all(target_arch = "x86_64", any(feature = "nightly_stdsimd", feature = "avx512_simd")))]
164+
unsafe impl Pod for x86_64::{
165+
__m512, __m512d, __m512i
166+
}
167+
);
168+
155169
impl_unsafe_marker_for_simd!(
156170
#[cfg(all(target_arch = "x86", feature = "nightly_stdsimd"))]
157171
unsafe impl Pod for x86::{
158-
__m128bh, __m256bh, __m512,
159-
__m512bh, __m512d, __m512i,
172+
__m128bh, __m256bh, __m512bh
160173
}
161174
);
162175

163176
impl_unsafe_marker_for_simd!(
164177
#[cfg(all(target_arch = "x86_64", feature = "nightly_stdsimd"))]
165178
unsafe impl Pod for x86_64::{
166-
__m128bh, __m256bh, __m512,
167-
__m512bh, __m512d, __m512i,
179+
__m128bh, __m256bh, __m512bh
168180
}
169181
);

src/zeroable.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,18 +232,30 @@ where
232232
{
233233
}
234234

235+
impl_unsafe_marker_for_simd!(
236+
#[cfg(all(target_arch = "x86", any(feature = "nightly_stdsimd", feature = "avx512_simd")))]
237+
unsafe impl Zeroable for x86::{
238+
__m512, __m512d, __m512i
239+
}
240+
);
241+
242+
impl_unsafe_marker_for_simd!(
243+
#[cfg(all(target_arch = "x86_64", any(feature = "nightly_stdsimd", feature = "avx512_simd")))]
244+
unsafe impl Zeroable for x86_64::{
245+
__m512, __m512d, __m512i
246+
}
247+
);
248+
235249
impl_unsafe_marker_for_simd!(
236250
#[cfg(all(target_arch = "x86", feature = "nightly_stdsimd"))]
237251
unsafe impl Zeroable for x86::{
238-
__m128bh, __m256bh, __m512,
239-
__m512bh, __m512d, __m512i,
252+
__m128bh, __m256bh, __m512bh
240253
}
241254
);
242255

243256
impl_unsafe_marker_for_simd!(
244257
#[cfg(all(target_arch = "x86_64", feature = "nightly_stdsimd"))]
245258
unsafe impl Zeroable for x86_64::{
246-
__m128bh, __m256bh, __m512,
247-
__m512bh, __m512d, __m512i,
259+
__m128bh, __m256bh, __m512bh
248260
}
249261
);

0 commit comments

Comments
 (0)