• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
6 use crate::{AnyBitPattern, NoUninit};
7 use core::mem::{align_of, size_of};
8 
9 struct Cast<A, B>((A, B));
10 impl<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]
must_cast<A: NoUninit, B: AnyBitPattern>(a: A) -> B41 pub 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]
must_cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> &B67 pub 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 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   }
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]
must_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B]149 pub 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 
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   }
212 }
213