bytemuck/must.rs
1#![allow(clippy::module_name_repetitions)]
2#![allow(clippy::let_unit_value)]
3#![allow(clippy::let_underscore_untyped)]
4#![allow(clippy::ptr_as_ptr)]
5
6use crate::{AnyBitPattern, NoUninit};
7use core::mem::{align_of, size_of};
8
9struct Cast<A, B>((A, B));
10impl<A, B> Cast<A, B> {
11 const ASSERT_ALIGN_GREATER_THAN_EQUAL: () =
12 assert!(align_of::<A>() >= align_of::<B>());
13 const ASSERT_SIZE_EQUAL: () = assert!(size_of::<A>() == size_of::<B>());
14 const ASSERT_SIZE_MULTIPLE_OF_OR_INPUT_ZST: () = assert!(
15 (size_of::<A>() == 0)
16 || (size_of::<B>() != 0 && size_of::<A>() % size_of::<B>() == 0)
17 );
18}
19
20/// Cast `A` into `B` if infalliable, or fail to compile.
21///
22/// Note that for this particular type of cast, alignment isn't a factor. The
23/// input value is semantically copied into the function and then returned to a
24/// new memory location which will have whatever the required alignment of the
25/// output type is.
26///
27/// ## Failure
28///
29/// * If the types don't have the same size this fails to compile.
30///
31/// ## Examples
32/// ```
33/// // compiles:
34/// let bytes: [u8; 2] = bytemuck::must_cast(12_u16);
35/// ```
36/// ```compile_fail,E0080
37/// // fails to compile (size mismatch):
38/// let bytes : [u8; 3] = bytemuck::must_cast(12_u16);
39/// ```
40#[inline]
41pub const fn must_cast<A: NoUninit, B: AnyBitPattern>(a: A) -> B {
42 let _ = Cast::<A, B>::ASSERT_SIZE_EQUAL;
43 unsafe { transmute!(A; B; a) }
44}
45
46/// Convert `&A` into `&B` if infalliable, or fail to compile.
47///
48/// ## Failure
49///
50/// * If the target type has a greater alignment requirement.
51/// * If the source type and target type aren't the same size.
52///
53/// ## Examples
54/// ```
55/// // compiles:
56/// let bytes: &[u8; 2] = bytemuck::must_cast_ref(&12_u16);
57/// ```
58/// ```compile_fail,E0080
59/// // fails to compile (size mismatch):
60/// let bytes : &[u8; 3] = bytemuck::must_cast_ref(&12_u16);
61/// ```
62/// ```compile_fail,E0080
63/// // fails to compile (alignment requirements increased):
64/// let bytes : &u16 = bytemuck::must_cast_ref(&[1u8, 2u8]);
65/// ```
66#[inline]
67pub const fn must_cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> &B {
68 let _ = Cast::<A, B>::ASSERT_SIZE_EQUAL;
69 let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
70 unsafe { &*(a as *const A as *const B) }
71}
72
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]
94pub 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) }
103}
104
105/// Convert `&[A]` into `&[B]` (possibly with a change in length) if
106/// infalliable, or fail to compile.
107///
108/// * `input.as_ptr() as usize == output.as_ptr() as usize`
109/// * `input.len() * size_of::<A>() == output.len() * size_of::<B>()`
110///
111/// ## Failure
112///
113/// * If the target type has a greater alignment requirement.
114/// * If the target element type doesn't evenly fit into the the current element
115/// type (eg: 3 `u16` values is 1.5 `u32` values, so that's a failure).
116/// * Similarly, you can't convert from a non-[ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts)
117/// to a ZST (e.g. 3 `u8` values is not any number of `()` values).
118///
119/// ## Examples
120/// ```
121/// let indicies: &[u16] = &[1, 2, 3];
122/// // compiles:
123/// let bytes: &[u8] = bytemuck::must_cast_slice(indicies);
124/// ```
125/// ```
126/// let zsts: &[()] = &[(), (), ()];
127/// // compiles:
128/// let bytes: &[u8] = bytemuck::must_cast_slice(zsts);
129/// ```
130/// ```compile_fail,E0080
131/// # let bytes : &[u8] = &[1, 0, 2, 0, 3, 0];
132/// // fails to compile (bytes.len() might not be a multiple of 2):
133/// let byte_pairs : &[[u8; 2]] = bytemuck::must_cast_slice(bytes);
134/// ```
135/// ```compile_fail,E0080
136/// # let byte_pairs : &[[u8; 2]] = &[[1, 0], [2, 0], [3, 0]];
137/// // fails to compile (alignment requirements increased):
138/// let indicies : &[u16] = bytemuck::must_cast_slice(byte_pairs);
139/// ```
140/// ```compile_fail,E0080
141/// let bytes: &[u8] = &[];
142/// // fails to compile: (bytes.len() might not be 0)
143/// let zsts: &[()] = bytemuck::must_cast_slice(bytes);
144/// ```
145#[inline]
146pub const fn must_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B] {
147 let _ = Cast::<A, B>::ASSERT_SIZE_MULTIPLE_OF_OR_INPUT_ZST;
148 let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
149 let new_len = if size_of::<A>() == size_of::<B>() {
150 a.len()
151 } else {
152 a.len() * (size_of::<A>() / size_of::<B>())
153 };
154 unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) }
155}
156
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]
192pub 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) }
206}