xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/bytemuck-1.15.0/src/must.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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: () = assert!(
15     (size_of::<A>() == 0) == (size_of::<B>() == 0)
16       && (size_of::<A>() % size_of::<B>() == 0)
17   );
18 }
19 
20 // Workaround for https://github.com/rust-lang/miri/issues/2423.
21 // Miri currently doesn't see post-monomorphization errors until runtime,
22 // so `compile_fail` tests relying on post-monomorphization errors don't
23 // actually fail. Instead use `should_panic` under miri as a workaround.
24 #[cfg(miri)]
25 macro_rules! post_mono_compile_fail_doctest {
26   () => {
27     "```should_panic"
28   };
29 }
30 #[cfg(not(miri))]
31 macro_rules! post_mono_compile_fail_doctest {
32   () => {
33     "```compile_fail,E0080"
34   };
35 }
36 
37 /// Cast `A` into `B` if infalliable, or fail to compile.
38 ///
39 /// Note that for this particular type of cast, alignment isn't a factor. The
40 /// input value is semantically copied into the function and then returned to a
41 /// new memory location which will have whatever the required alignment of the
42 /// output type is.
43 ///
44 /// ## Failure
45 ///
46 /// * If the types don't have the same size this fails to compile.
47 ///
48 /// ## Examples
49 /// ```
50 /// // compiles:
51 /// let bytes: [u8; 2] = bytemuck::must_cast(12_u16);
52 /// ```
53 #[doc = post_mono_compile_fail_doctest!()]
54 /// // fails to compile (size mismatch):
55 /// let bytes : [u8; 3] = bytemuck::must_cast(12_u16);
56 /// ```
57 #[inline]
must_cast<A: NoUninit, B: AnyBitPattern>(a: A) -> B58 pub fn must_cast<A: NoUninit, B: AnyBitPattern>(a: A) -> B {
59   let _ = Cast::<A, B>::ASSERT_SIZE_EQUAL;
60   unsafe { transmute!(a) }
61 }
62 
63 /// Convert `&A` into `&B` if infalliable, or fail to compile.
64 ///
65 /// ## Failure
66 ///
67 /// * If the target type has a greater alignment requirement.
68 /// * If the source type and target type aren't the same size.
69 ///
70 /// ## Examples
71 /// ```
72 /// // compiles:
73 /// let bytes: &[u8; 2] = bytemuck::must_cast_ref(&12_u16);
74 /// ```
75 #[doc = post_mono_compile_fail_doctest!()]
76 /// // fails to compile (size mismatch):
77 /// let bytes : &[u8; 3] = bytemuck::must_cast_ref(&12_u16);
78 /// ```
79 #[doc = post_mono_compile_fail_doctest!()]
80 /// // fails to compile (alignment requirements increased):
81 /// let bytes : &u16 = bytemuck::must_cast_ref(&[1u8, 2u8]);
82 /// ```
83 #[inline]
must_cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> &B84 pub fn must_cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> &B {
85   let _ = Cast::<A, B>::ASSERT_SIZE_EQUAL;
86   let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
87   unsafe { &*(a as *const A as *const B) }
88 }
89 
90 /// Convert a `&mut A` into `&mut B` if infalliable, or fail to compile.
91 ///
92 /// As [`must_cast_ref`], but `mut`.
93 ///
94 /// ## Examples
95 /// ```
96 /// let mut i = 12_u16;
97 /// // compiles:
98 /// let bytes: &mut [u8; 2] = bytemuck::must_cast_mut(&mut i);
99 /// ```
100 #[doc = post_mono_compile_fail_doctest!()]
101 /// # let mut bytes: &mut [u8; 2] = &mut [1, 2];
102 /// // fails to compile (alignment requirements increased):
103 /// let i : &mut u16 = bytemuck::must_cast_mut(bytes);
104 /// ```
105 #[doc = post_mono_compile_fail_doctest!()]
106 /// # let mut i = 12_u16;
107 /// // fails to compile (size mismatch):
108 /// let bytes : &mut [u8; 3] = bytemuck::must_cast_mut(&mut i);
109 /// ```
110 #[inline]
must_cast_mut< A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern, >( a: &mut A, ) -> &mut B111 pub fn must_cast_mut<
112   A: NoUninit + AnyBitPattern,
113   B: NoUninit + AnyBitPattern,
114 >(
115   a: &mut A,
116 ) -> &mut B {
117   let _ = Cast::<A, B>::ASSERT_SIZE_EQUAL;
118   let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
119   unsafe { &mut *(a as *mut A as *mut B) }
120 }
121 
122 /// Convert `&[A]` into `&[B]` (possibly with a change in length) if
123 /// infalliable, or fail to compile.
124 ///
125 /// * `input.as_ptr() as usize == output.as_ptr() as usize`
126 /// * `input.len() * size_of::<A>() == output.len() * size_of::<B>()`
127 ///
128 /// ## Failure
129 ///
130 /// * If the target type has a greater alignment requirement.
131 /// * If the target element type doesn't evenly fit into the the current element
132 ///   type (eg: 3 `u16` values is 1.5 `u32` values, so that's a failure).
133 /// * Similarly, you can't convert between a [ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts)
134 ///   and a non-ZST.
135 ///
136 /// ## Examples
137 /// ```
138 /// let indicies: &[u16] = &[1, 2, 3];
139 /// // compiles:
140 /// let bytes: &[u8] = bytemuck::must_cast_slice(indicies);
141 /// ```
142 #[doc = post_mono_compile_fail_doctest!()]
143 /// # let bytes : &[u8] = &[1, 0, 2, 0, 3, 0];
144 /// // fails to compile (bytes.len() might not be a multiple of 2):
145 /// let byte_pairs : &[[u8; 2]] = bytemuck::must_cast_slice(bytes);
146 /// ```
147 #[doc = post_mono_compile_fail_doctest!()]
148 /// # let byte_pairs : &[[u8; 2]] = &[[1, 0], [2, 0], [3, 0]];
149 /// // fails to compile (alignment requirements increased):
150 /// let indicies : &[u16] = bytemuck::must_cast_slice(byte_pairs);
151 /// ```
152 #[inline]
must_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B]153 pub fn must_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B] {
154   let _ = Cast::<A, B>::ASSERT_SIZE_MULTIPLE_OF;
155   let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
156   let new_len = if size_of::<A>() == size_of::<B>() {
157     a.len()
158   } else {
159     a.len() * (size_of::<A>() / size_of::<B>())
160   };
161   unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) }
162 }
163 
164 /// Convert `&mut [A]` into `&mut [B]` (possibly with a change in length) if
165 /// infalliable, or fail to compile.
166 ///
167 /// As [`must_cast_slice`], but `&mut`.
168 ///
169 /// ## Examples
170 /// ```
171 /// let mut indicies = [1, 2, 3];
172 /// let indicies: &mut [u16] = &mut indicies;
173 /// // compiles:
174 /// let bytes: &mut [u8] = bytemuck::must_cast_slice_mut(indicies);
175 /// ```
176 #[doc = post_mono_compile_fail_doctest!()]
177 /// # let mut bytes = [1, 0, 2, 0, 3, 0];
178 /// # let bytes : &mut [u8] = &mut bytes[..];
179 /// // fails to compile (bytes.len() might not be a multiple of 2):
180 /// let byte_pairs : &mut [[u8; 2]] = bytemuck::must_cast_slice_mut(bytes);
181 /// ```
182 #[doc = post_mono_compile_fail_doctest!()]
183 /// # let mut byte_pairs = [[1, 0], [2, 0], [3, 0]];
184 /// # let byte_pairs : &mut [[u8; 2]] = &mut byte_pairs[..];
185 /// // fails to compile (alignment requirements increased):
186 /// let indicies : &mut [u16] = bytemuck::must_cast_slice_mut(byte_pairs);
187 /// ```
188 #[inline]
must_cast_slice_mut< A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern, >( a: &mut [A], ) -> &mut [B]189 pub fn must_cast_slice_mut<
190   A: NoUninit + AnyBitPattern,
191   B: NoUninit + AnyBitPattern,
192 >(
193   a: &mut [A],
194 ) -> &mut [B] {
195   let _ = Cast::<A, B>::ASSERT_SIZE_MULTIPLE_OF;
196   let _ = Cast::<A, B>::ASSERT_ALIGN_GREATER_THAN_EQUAL;
197   let new_len = if size_of::<A>() == size_of::<B>() {
198     a.len()
199   } else {
200     a.len() * (size_of::<A>() / size_of::<B>())
201   };
202   unsafe { core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) }
203 }
204