1#![allow(unused_unsafe)]
6
7use crate::PodCastError;
8use core::{marker::*, mem::*};
9
10#[cfg(not(target_arch = "spirv"))]
24#[cold]
25#[inline(never)]
26pub(crate) fn something_went_wrong<D: core::fmt::Display>(
27 _src: &str, _err: D,
28) -> ! {
29 panic!("{src}>{err}", src = _src, err = _err);
33}
34
35#[cfg(target_arch = "spirv")]
37#[cold]
38#[inline(never)]
39pub(crate) fn something_went_wrong<D>(_src: &str, _err: D) -> ! {
40 panic!("Called a panicing helper from bytemuck which paniced");
46}
47
48#[inline(always)]
53pub(crate) unsafe fn bytes_of<T: Copy>(t: &T) -> &[u8] {
54 match try_cast_slice::<T, u8>(core::slice::from_ref(t)) {
55 Ok(s) => s,
56 Err(_) => unreachable!(),
57 }
58}
59
60#[inline]
65pub(crate) unsafe fn bytes_of_mut<T: Copy>(t: &mut T) -> &mut [u8] {
66 match try_cast_slice_mut::<T, u8>(core::slice::from_mut(t)) {
67 Ok(s) => s,
68 Err(_) => unreachable!(),
69 }
70}
71
72#[inline]
78pub(crate) unsafe fn from_bytes<T: Copy>(s: &[u8]) -> &T {
79 match try_from_bytes(s) {
80 Ok(t) => t,
81 Err(e) => something_went_wrong("from_bytes", e),
82 }
83}
84
85#[inline]
91pub(crate) unsafe fn from_bytes_mut<T: Copy>(s: &mut [u8]) -> &mut T {
92 match try_from_bytes_mut(s) {
93 Ok(t) => t,
94 Err(e) => something_went_wrong("from_bytes_mut", e),
95 }
96}
97
98#[inline]
103pub(crate) unsafe fn try_pod_read_unaligned<T: Copy>(
104 bytes: &[u8],
105) -> Result<T, PodCastError> {
106 if bytes.len() != size_of::<T>() {
107 Err(PodCastError::SizeMismatch)
108 } else {
109 Ok(unsafe { (bytes.as_ptr() as *const T).read_unaligned() })
110 }
111}
112
113#[inline]
118pub(crate) unsafe fn pod_read_unaligned<T: Copy>(bytes: &[u8]) -> T {
119 match try_pod_read_unaligned(bytes) {
120 Ok(t) => t,
121 Err(e) => something_went_wrong("pod_read_unaligned", e),
122 }
123}
124
125#[inline]
130pub(crate) fn is_aligned_to(ptr: *const (), align: usize) -> bool {
131 #[cfg(feature = "align_offset")]
132 {
133 ptr.align_offset(align) == 0
138 }
139 #[cfg(not(feature = "align_offset"))]
140 {
141 ((ptr as usize) % align) == 0
142 }
143}
144
145#[inline]
152pub(crate) unsafe fn try_from_bytes<T: Copy>(
153 s: &[u8],
154) -> Result<&T, PodCastError> {
155 if s.len() != size_of::<T>() {
156 Err(PodCastError::SizeMismatch)
157 } else if !is_aligned_to(s.as_ptr() as *const (), align_of::<T>()) {
158 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
159 } else {
160 Ok(unsafe { &*(s.as_ptr() as *const T) })
161 }
162}
163
164#[inline]
171pub(crate) unsafe fn try_from_bytes_mut<T: Copy>(
172 s: &mut [u8],
173) -> Result<&mut T, PodCastError> {
174 if s.len() != size_of::<T>() {
175 Err(PodCastError::SizeMismatch)
176 } else if !is_aligned_to(s.as_ptr() as *const (), align_of::<T>()) {
177 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
178 } else {
179 Ok(unsafe { &mut *(s.as_mut_ptr() as *mut T) })
180 }
181}
182
183#[inline]
189pub(crate) unsafe fn cast<A: Copy, B: Copy>(a: A) -> B {
190 if size_of::<A>() == size_of::<B>() {
191 unsafe { transmute!(a) }
192 } else {
193 something_went_wrong("cast", PodCastError::SizeMismatch)
194 }
195}
196
197#[inline]
203pub(crate) unsafe fn cast_mut<A: Copy, B: Copy>(a: &mut A) -> &mut B {
204 if size_of::<A>() == size_of::<B>() && align_of::<A>() >= align_of::<B>() {
205 match try_cast_mut(a) {
207 Ok(b) => b,
208 Err(_) => unreachable!(),
209 }
210 } else {
211 match try_cast_mut(a) {
212 Ok(b) => b,
213 Err(e) => something_went_wrong("cast_mut", e),
214 }
215 }
216}
217
218#[inline]
224pub(crate) unsafe fn cast_ref<A: Copy, B: Copy>(a: &A) -> &B {
225 if size_of::<A>() == size_of::<B>() && align_of::<A>() >= align_of::<B>() {
226 match try_cast_ref(a) {
228 Ok(b) => b,
229 Err(_) => unreachable!(),
230 }
231 } else {
232 match try_cast_ref(a) {
233 Ok(b) => b,
234 Err(e) => something_went_wrong("cast_ref", e),
235 }
236 }
237}
238
239#[inline]
245pub(crate) unsafe fn cast_slice<A: Copy, B: Copy>(a: &[A]) -> &[B] {
246 match try_cast_slice(a) {
247 Ok(b) => b,
248 Err(e) => something_went_wrong("cast_slice", e),
249 }
250}
251
252#[inline]
258pub(crate) unsafe fn cast_slice_mut<A: Copy, B: Copy>(a: &mut [A]) -> &mut [B] {
259 match try_cast_slice_mut(a) {
260 Ok(b) => b,
261 Err(e) => something_went_wrong("cast_slice_mut", e),
262 }
263}
264
265#[inline]
276pub(crate) unsafe fn try_cast<A: Copy, B: Copy>(
277 a: A,
278) -> Result<B, PodCastError> {
279 if size_of::<A>() == size_of::<B>() {
280 Ok(unsafe { transmute!(a) })
281 } else {
282 Err(PodCastError::SizeMismatch)
283 }
284}
285
286#[inline]
293pub(crate) unsafe fn try_cast_ref<A: Copy, B: Copy>(
294 a: &A,
295) -> Result<&B, PodCastError> {
296 if align_of::<B>() > align_of::<A>()
299 && !is_aligned_to(a as *const A as *const (), align_of::<B>())
300 {
301 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
302 } else if size_of::<B>() == size_of::<A>() {
303 Ok(unsafe { &*(a as *const A as *const B) })
304 } else {
305 Err(PodCastError::SizeMismatch)
306 }
307}
308
309#[inline]
313pub(crate) unsafe fn try_cast_mut<A: Copy, B: Copy>(
314 a: &mut A,
315) -> Result<&mut B, PodCastError> {
316 if align_of::<B>() > align_of::<A>()
319 && !is_aligned_to(a as *const A as *const (), align_of::<B>())
320 {
321 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
322 } else if size_of::<B>() == size_of::<A>() {
323 Ok(unsafe { &mut *(a as *mut A as *mut B) })
324 } else {
325 Err(PodCastError::SizeMismatch)
326 }
327}
328
329#[inline]
343pub(crate) unsafe fn try_cast_slice<A: Copy, B: Copy>(
344 a: &[A],
345) -> Result<&[B], PodCastError> {
346 let input_bytes = core::mem::size_of_val::<[A]>(a);
347 if align_of::<B>() > align_of::<A>()
350 && !is_aligned_to(a.as_ptr() as *const (), align_of::<B>())
351 {
352 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
353 } else if size_of::<B>() == size_of::<A>() {
354 Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, a.len()) })
355 } else if (size_of::<B>() != 0 && input_bytes % size_of::<B>() == 0)
356 || (size_of::<B>() == 0 && input_bytes == 0)
357 {
358 let new_len =
359 if size_of::<B>() != 0 { input_bytes / size_of::<B>() } else { 0 };
360 Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) })
361 } else {
362 Err(PodCastError::OutputSliceWouldHaveSlop)
363 }
364}
365
366#[inline]
371pub(crate) unsafe fn try_cast_slice_mut<A: Copy, B: Copy>(
372 a: &mut [A],
373) -> Result<&mut [B], PodCastError> {
374 let input_bytes = core::mem::size_of_val::<[A]>(a);
375 if align_of::<B>() > align_of::<A>()
378 && !is_aligned_to(a.as_ptr() as *const (), align_of::<B>())
379 {
380 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
381 } else if size_of::<B>() == size_of::<A>() {
382 Ok(unsafe {
383 core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len())
384 })
385 } else if (size_of::<B>() != 0 && input_bytes % size_of::<B>() == 0)
386 || (size_of::<B>() == 0 && input_bytes == 0)
387 {
388 let new_len =
389 if size_of::<B>() != 0 { input_bytes / size_of::<B>() } else { 0 };
390 Ok(unsafe {
391 core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len)
392 })
393 } else {
394 Err(PodCastError::OutputSliceWouldHaveSlop)
395 }
396}