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
73maybe_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  }
106}
107
108/// Convert `&[A]` into `&[B]` (possibly with a change in length) if
109/// infalliable, or fail to compile.
110///
111/// * `input.as_ptr() as usize == output.as_ptr() as usize`
112/// * `input.len() * size_of::<A>() == output.len() * size_of::<B>()`
113///
114/// ## Failure
115///
116/// * If the target type has a greater alignment requirement.
117/// * If the target element type doesn't evenly fit into the the current element
118///   type (eg: 3 `u16` values is 1.5 `u32` values, so that's a failure).
119/// * Similarly, you can't convert from a non-[ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts)
120///   to a ZST (e.g. 3 `u8` values is not any number of `()` values).
121///
122/// ## Examples
123/// ```
124/// let indicies: &[u16] = &[1, 2, 3];
125/// // compiles:
126/// let bytes: &[u8] = bytemuck::must_cast_slice(indicies);
127/// ```
128/// ```
129/// let zsts: &[()] = &[(), (), ()];
130/// // compiles:
131/// let bytes: &[u8] = bytemuck::must_cast_slice(zsts);
132/// ```
133/// ```compile_fail,E0080
134/// # let bytes : &[u8] = &[1, 0, 2, 0, 3, 0];
135/// // fails to compile (bytes.len() might not be a multiple of 2):
136/// let byte_pairs : &[[u8; 2]] = bytemuck::must_cast_slice(bytes);
137/// ```
138/// ```compile_fail,E0080
139/// # let byte_pairs : &[[u8; 2]] = &[[1, 0], [2, 0], [3, 0]];
140/// // fails to compile (alignment requirements increased):
141/// let indicies : &[u16] = bytemuck::must_cast_slice(byte_pairs);
142/// ```
143/// ```compile_fail,E0080
144/// let bytes: &[u8] = &[];
145/// // fails to compile: (bytes.len() might not be 0)
146/// let zsts: &[()] = bytemuck::must_cast_slice(bytes);
147/// ```
148#[inline]
149pub const fn must_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B] {
150  let _ = Cast::<A, B>::ASSERT_SIZE_MULTIPLE_OF_OR_INPUT_ZST;
151  let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
152  let new_len = if size_of::<A>() == size_of::<B>() {
153    a.len()
154  } else {
155    a.len() * (size_of::<A>() / size_of::<B>())
156  };
157  unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) }
158}
159
160maybe_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  }
212}