1 #![no_std]
2 #![warn(missing_docs)]
3 #![allow(clippy::match_like_matches_macro)]
4 #![allow(clippy::uninlined_format_args)]
5 #![cfg_attr(feature = "nightly_docs", feature(doc_cfg))]
6 #![cfg_attr(feature = "nightly_portable_simd", feature(portable_simd))]
7 #![cfg_attr(feature = "nightly_stdsimd", feature(stdsimd))]
8
9 //! This crate gives small utilities for casting between plain data types.
10 //!
11 //! ## Basics
12 //!
13 //! Data comes in five basic forms in Rust, so we have five basic casting
14 //! functions:
15 //!
16 //! * `T` uses [`cast`]
17 //! * `&T` uses [`cast_ref`]
18 //! * `&mut T` uses [`cast_mut`]
19 //! * `&[T]` uses [`cast_slice`]
20 //! * `&mut [T]` uses [`cast_slice_mut`]
21 //!
22 //! Depending on the function, the [`NoUninit`] and/or [`AnyBitPattern`] traits
23 //! are used to maintain memory safety.
24 //!
25 //! **Historical Note:** When the crate first started the [`Pod`] trait was used
26 //! instead, and so you may hear people refer to that, but it has the strongest
27 //! requirements and people eventually wanted the more fine-grained system, so
28 //! here we are. All types that impl `Pod` have a blanket impl to also support
29 //! `NoUninit` and `AnyBitPattern`. The traits unfortunately do not have a
30 //! perfectly clean hierarchy for semver reasons.
31 //!
32 //! ## Failures
33 //!
34 //! Some casts will never fail, and other casts might fail.
35 //!
36 //! * `cast::<u32, f32>` always works (and [`f32::from_bits`]).
37 //! * `cast_ref::<[u8; 4], u32>` might fail if the specific array reference
38 //! given at runtime doesn't have alignment 4.
39 //!
40 //! In addition to the "normal" forms of each function, which will panic on
41 //! invalid input, there's also `try_` versions which will return a `Result`.
42 //!
43 //! If you would like to statically ensure that a cast will work at runtime you
44 //! can use the `must_cast` crate feature and the `must_` casting functions. A
45 //! "must cast" that can't be statically known to be valid will cause a
46 //! compilation error (and sometimes a very hard to read compilation error).
47 //!
48 //! ## Using Your Own Types
49 //!
50 //! All the functions listed above are guarded by the [`Pod`] trait, which is a
51 //! sub-trait of the [`Zeroable`] trait.
52 //!
53 //! If you enable the crate's `derive` feature then these traits can be derived
54 //! on your own types. The derive macros will perform the necessary checks on
55 //! your type declaration, and trigger an error if your type does not qualify.
56 //!
57 //! The derive macros might not cover all edge cases, and sometimes they will
58 //! error when actually everything is fine. As a last resort you can impl these
59 //! traits manually. However, these traits are `unsafe`, and you should
60 //! carefully read the requirements before using a manual implementation.
61 //!
62 //! ## Cargo Features
63 //!
64 //! The crate supports Rust 1.34 when no features are enabled, and so there's
65 //! cargo features for thing that you might consider "obvious".
66 //!
67 //! The cargo features **do not** promise any particular MSRV, and they may
68 //! increase their MSRV in new versions.
69 //!
70 //! * `derive`: Provide derive macros for the various traits.
71 //! * `extern_crate_alloc`: Provide utilities for `alloc` related types such as
72 //! Box and Vec.
73 //! * `zeroable_maybe_uninit` and `zeroable_atomics`: Provide more [`Zeroable`]
74 //! impls.
75 //! * `wasm_simd` and `aarch64_simd`: Support more SIMD types.
76 //! * `min_const_generics`: Provides appropriate impls for arrays of all lengths
77 //! instead of just for a select list of array lengths.
78 //! * `must_cast`: Provides the `must_` functions, which will compile error if
79 //! the requested cast can't be statically verified.
80
81 #[cfg(all(target_arch = "aarch64", feature = "aarch64_simd"))]
82 use core::arch::aarch64;
83 #[cfg(all(target_arch = "wasm32", feature = "wasm_simd"))]
84 use core::arch::wasm32;
85 #[cfg(target_arch = "x86")]
86 use core::arch::x86;
87 #[cfg(target_arch = "x86_64")]
88 use core::arch::x86_64;
89 //
90 use core::{marker::*, mem::*, num::*, ptr::*};
91
92 // Used from macros to ensure we aren't using some locally defined name and
93 // actually are referencing libcore. This also would allow pre-2018 edition
94 // crates to use our macros, but I'm not sure how important that is.
95 #[doc(hidden)]
96 pub use ::core as __core;
97
98 #[cfg(not(feature = "min_const_generics"))]
99 macro_rules! impl_unsafe_marker_for_array {
100 ( $marker:ident , $( $n:expr ),* ) => {
101 $(unsafe impl<T> $marker for [T; $n] where T: $marker {})*
102 }
103 }
104
105 /// A macro to transmute between two types without requiring knowing size
106 /// statically.
107 macro_rules! transmute {
108 ($val:expr) => {
109 ::core::mem::transmute_copy(&::core::mem::ManuallyDrop::new($val))
110 };
111 }
112
113 /// A macro to implement marker traits for various simd types.
114 /// #[allow(unused)] because the impls are only compiled on relevant platforms
115 /// with relevant cargo features enabled.
116 #[allow(unused)]
117 macro_rules! impl_unsafe_marker_for_simd {
118 ($(#[cfg($cfg_predicate:meta)])? unsafe impl $trait:ident for $platform:ident :: {}) => {};
119 ($(#[cfg($cfg_predicate:meta)])? unsafe impl $trait:ident for $platform:ident :: { $first_type:ident $(, $types:ident)* $(,)? }) => {
120 $( #[cfg($cfg_predicate)] )?
121 $( #[cfg_attr(feature = "nightly_docs", doc(cfg($cfg_predicate)))] )?
122 unsafe impl $trait for $platform::$first_type {}
123 $( #[cfg($cfg_predicate)] )? // To prevent recursion errors if nothing is going to be expanded anyway.
124 impl_unsafe_marker_for_simd!($( #[cfg($cfg_predicate)] )? unsafe impl $trait for $platform::{ $( $types ),* });
125 };
126 }
127
128 #[cfg(feature = "extern_crate_std")]
129 extern crate std;
130
131 #[cfg(feature = "extern_crate_alloc")]
132 extern crate alloc;
133 #[cfg(feature = "extern_crate_alloc")]
134 #[cfg_attr(feature = "nightly_docs", doc(cfg(feature = "extern_crate_alloc")))]
135 pub mod allocation;
136 #[cfg(feature = "extern_crate_alloc")]
137 pub use allocation::*;
138
139 mod anybitpattern;
140 pub use anybitpattern::*;
141
142 pub mod checked;
143 pub use checked::CheckedBitPattern;
144
145 mod internal;
146
147 mod zeroable;
148 pub use zeroable::*;
149 mod zeroable_in_option;
150 pub use zeroable_in_option::*;
151
152 mod pod;
153 pub use pod::*;
154 mod pod_in_option;
155 pub use pod_in_option::*;
156
157 #[cfg(feature = "must_cast")]
158 mod must;
159 #[cfg(feature = "must_cast")]
160 #[cfg_attr(feature = "nightly_docs", doc(cfg(feature = "must_cast")))]
161 pub use must::*;
162
163 mod no_uninit;
164 pub use no_uninit::*;
165
166 mod contiguous;
167 pub use contiguous::*;
168
169 mod offset_of;
170 // ^ no import, the module only has a macro_rules, which are cursed and don't
171 // follow normal import/export rules.
172
173 mod transparent;
174 pub use transparent::*;
175
176 #[cfg(feature = "derive")]
177 #[cfg_attr(feature = "nightly_docs", doc(cfg(feature = "derive")))]
178 pub use bytemuck_derive::{
179 AnyBitPattern, ByteEq, ByteHash, CheckedBitPattern, Contiguous, NoUninit,
180 Pod, TransparentWrapper, Zeroable,
181 };
182
183 /// The things that can go wrong when casting between [`Pod`] data forms.
184 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
185 pub enum PodCastError {
186 /// You tried to cast a slice to an element type with a higher alignment
187 /// requirement but the slice wasn't aligned.
188 TargetAlignmentGreaterAndInputNotAligned,
189 /// If the element size changes then the output slice changes length
190 /// accordingly. If the output slice wouldn't be a whole number of elements
191 /// then the conversion fails.
192 OutputSliceWouldHaveSlop,
193 /// When casting a slice you can't convert between ZST elements and non-ZST
194 /// elements. When casting an individual `T`, `&T`, or `&mut T` value the
195 /// source size and destination size must be an exact match.
196 SizeMismatch,
197 /// For this type of cast the alignments must be exactly the same and they
198 /// were not so now you're sad.
199 ///
200 /// This error is generated **only** by operations that cast allocated types
201 /// (such as `Box` and `Vec`), because in that case the alignment must stay
202 /// exact.
203 AlignmentMismatch,
204 }
205 #[cfg(not(target_arch = "spirv"))]
206 impl core::fmt::Display for PodCastError {
fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result207 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
208 write!(f, "{:?}", self)
209 }
210 }
211 #[cfg(feature = "extern_crate_std")]
212 #[cfg_attr(feature = "nightly_docs", doc(cfg(feature = "extern_crate_std")))]
213 impl std::error::Error for PodCastError {}
214
215 /// Re-interprets `&T` as `&[u8]`.
216 ///
217 /// Any ZST becomes an empty slice, and in that case the pointer value of that
218 /// empty slice might not match the pointer value of the input reference.
219 #[inline]
bytes_of<T: NoUninit>(t: &T) -> &[u8]220 pub fn bytes_of<T: NoUninit>(t: &T) -> &[u8] {
221 unsafe { internal::bytes_of(t) }
222 }
223
224 /// Re-interprets `&mut T` as `&mut [u8]`.
225 ///
226 /// Any ZST becomes an empty slice, and in that case the pointer value of that
227 /// empty slice might not match the pointer value of the input reference.
228 #[inline]
bytes_of_mut<T: NoUninit + AnyBitPattern>(t: &mut T) -> &mut [u8]229 pub fn bytes_of_mut<T: NoUninit + AnyBitPattern>(t: &mut T) -> &mut [u8] {
230 unsafe { internal::bytes_of_mut(t) }
231 }
232
233 /// Re-interprets `&[u8]` as `&T`.
234 ///
235 /// ## Panics
236 ///
237 /// This is like [`try_from_bytes`] but will panic on error.
238 #[inline]
from_bytes<T: AnyBitPattern>(s: &[u8]) -> &T239 pub fn from_bytes<T: AnyBitPattern>(s: &[u8]) -> &T {
240 unsafe { internal::from_bytes(s) }
241 }
242
243 /// Re-interprets `&mut [u8]` as `&mut T`.
244 ///
245 /// ## Panics
246 ///
247 /// This is like [`try_from_bytes_mut`] but will panic on error.
248 #[inline]
from_bytes_mut<T: NoUninit + AnyBitPattern>(s: &mut [u8]) -> &mut T249 pub fn from_bytes_mut<T: NoUninit + AnyBitPattern>(s: &mut [u8]) -> &mut T {
250 unsafe { internal::from_bytes_mut(s) }
251 }
252
253 /// Reads from the bytes as if they were a `T`.
254 ///
255 /// Unlike [`from_bytes`], the slice doesn't need to respect alignment of `T`, only sizes
256 /// must match.
257 ///
258 /// ## Failure
259 /// * If the `bytes` length is not equal to `size_of::<T>()`.
260 #[inline]
try_pod_read_unaligned<T: AnyBitPattern>( bytes: &[u8], ) -> Result<T, PodCastError>261 pub fn try_pod_read_unaligned<T: AnyBitPattern>(
262 bytes: &[u8],
263 ) -> Result<T, PodCastError> {
264 unsafe { internal::try_pod_read_unaligned(bytes) }
265 }
266
267 /// Reads the slice into a `T` value.
268 ///
269 /// Unlike [`from_bytes`], the slice doesn't need to respect alignment of `T`, only sizes
270 /// must match.
271 ///
272 /// ## Panics
273 /// * This is like `try_pod_read_unaligned` but will panic on failure.
274 #[inline]
pod_read_unaligned<T: AnyBitPattern>(bytes: &[u8]) -> T275 pub fn pod_read_unaligned<T: AnyBitPattern>(bytes: &[u8]) -> T {
276 unsafe { internal::pod_read_unaligned(bytes) }
277 }
278
279 /// Re-interprets `&[u8]` as `&T`.
280 ///
281 /// ## Failure
282 ///
283 /// * If the slice isn't aligned for the new type
284 /// * If the slice's length isn’t exactly the size of the new type
285 #[inline]
try_from_bytes<T: AnyBitPattern>(s: &[u8]) -> Result<&T, PodCastError>286 pub fn try_from_bytes<T: AnyBitPattern>(s: &[u8]) -> Result<&T, PodCastError> {
287 unsafe { internal::try_from_bytes(s) }
288 }
289
290 /// Re-interprets `&mut [u8]` as `&mut T`.
291 ///
292 /// ## Failure
293 ///
294 /// * If the slice isn't aligned for the new type
295 /// * If the slice's length isn’t exactly the size of the new type
296 #[inline]
try_from_bytes_mut<T: NoUninit + AnyBitPattern>( s: &mut [u8], ) -> Result<&mut T, PodCastError>297 pub fn try_from_bytes_mut<T: NoUninit + AnyBitPattern>(
298 s: &mut [u8],
299 ) -> Result<&mut T, PodCastError> {
300 unsafe { internal::try_from_bytes_mut(s) }
301 }
302
303 /// Cast `T` into `U`
304 ///
305 /// ## Panics
306 ///
307 /// * This is like [`try_cast`], but will panic on a size mismatch.
308 #[inline]
cast<A: NoUninit, B: AnyBitPattern>(a: A) -> B309 pub fn cast<A: NoUninit, B: AnyBitPattern>(a: A) -> B {
310 unsafe { internal::cast(a) }
311 }
312
313 /// Cast `&mut T` into `&mut U`.
314 ///
315 /// ## Panics
316 ///
317 /// This is [`try_cast_mut`] but will panic on error.
318 #[inline]
cast_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>( a: &mut A, ) -> &mut B319 pub fn cast_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
320 a: &mut A,
321 ) -> &mut B {
322 unsafe { internal::cast_mut(a) }
323 }
324
325 /// Cast `&T` into `&U`.
326 ///
327 /// ## Panics
328 ///
329 /// This is [`try_cast_ref`] but will panic on error.
330 #[inline]
cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> &B331 pub fn cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> &B {
332 unsafe { internal::cast_ref(a) }
333 }
334
335 /// Cast `&[A]` into `&[B]`.
336 ///
337 /// ## Panics
338 ///
339 /// This is [`try_cast_slice`] but will panic on error.
340 #[inline]
cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B]341 pub fn cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B] {
342 unsafe { internal::cast_slice(a) }
343 }
344
345 /// Cast `&mut [T]` into `&mut [U]`.
346 ///
347 /// ## Panics
348 ///
349 /// This is [`try_cast_slice_mut`] but will panic on error.
350 #[inline]
cast_slice_mut< A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern, >( a: &mut [A], ) -> &mut [B]351 pub fn cast_slice_mut<
352 A: NoUninit + AnyBitPattern,
353 B: NoUninit + AnyBitPattern,
354 >(
355 a: &mut [A],
356 ) -> &mut [B] {
357 unsafe { internal::cast_slice_mut(a) }
358 }
359
360 /// As [`align_to`](https://doc.rust-lang.org/std/primitive.slice.html#method.align_to),
361 /// but safe because of the [`Pod`] bound.
362 #[inline]
pod_align_to<T: NoUninit, U: AnyBitPattern>( vals: &[T], ) -> (&[T], &[U], &[T])363 pub fn pod_align_to<T: NoUninit, U: AnyBitPattern>(
364 vals: &[T],
365 ) -> (&[T], &[U], &[T]) {
366 unsafe { vals.align_to::<U>() }
367 }
368
369 /// As [`align_to_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.align_to_mut),
370 /// but safe because of the [`Pod`] bound.
371 #[inline]
pod_align_to_mut< T: NoUninit + AnyBitPattern, U: NoUninit + AnyBitPattern, >( vals: &mut [T], ) -> (&mut [T], &mut [U], &mut [T])372 pub fn pod_align_to_mut<
373 T: NoUninit + AnyBitPattern,
374 U: NoUninit + AnyBitPattern,
375 >(
376 vals: &mut [T],
377 ) -> (&mut [T], &mut [U], &mut [T]) {
378 unsafe { vals.align_to_mut::<U>() }
379 }
380
381 /// Try to cast `T` into `U`.
382 ///
383 /// Note that for this particular type of cast, alignment isn't a factor. The
384 /// input value is semantically copied into the function and then returned to a
385 /// new memory location which will have whatever the required alignment of the
386 /// output type is.
387 ///
388 /// ## Failure
389 ///
390 /// * If the types don't have the same size this fails.
391 #[inline]
try_cast<A: NoUninit, B: AnyBitPattern>( a: A, ) -> Result<B, PodCastError>392 pub fn try_cast<A: NoUninit, B: AnyBitPattern>(
393 a: A,
394 ) -> Result<B, PodCastError> {
395 unsafe { internal::try_cast(a) }
396 }
397
398 /// Try to convert a `&T` into `&U`.
399 ///
400 /// ## Failure
401 ///
402 /// * If the reference isn't aligned in the new type
403 /// * If the source type and target type aren't the same size.
404 #[inline]
try_cast_ref<A: NoUninit, B: AnyBitPattern>( a: &A, ) -> Result<&B, PodCastError>405 pub fn try_cast_ref<A: NoUninit, B: AnyBitPattern>(
406 a: &A,
407 ) -> Result<&B, PodCastError> {
408 unsafe { internal::try_cast_ref(a) }
409 }
410
411 /// Try to convert a `&mut T` into `&mut U`.
412 ///
413 /// As [`try_cast_ref`], but `mut`.
414 #[inline]
try_cast_mut< A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern, >( a: &mut A, ) -> Result<&mut B, PodCastError>415 pub fn try_cast_mut<
416 A: NoUninit + AnyBitPattern,
417 B: NoUninit + AnyBitPattern,
418 >(
419 a: &mut A,
420 ) -> Result<&mut B, PodCastError> {
421 unsafe { internal::try_cast_mut(a) }
422 }
423
424 /// Try to convert `&[A]` into `&[B]` (possibly with a change in length).
425 ///
426 /// * `input.as_ptr() as usize == output.as_ptr() as usize`
427 /// * `input.len() * size_of::<A>() == output.len() * size_of::<B>()`
428 ///
429 /// ## Failure
430 ///
431 /// * If the target type has a greater alignment requirement and the input slice
432 /// isn't aligned.
433 /// * If the target element type is a different size from the current element
434 /// type, and the output slice wouldn't be a whole number of elements when
435 /// accounting for the size change (eg: 3 `u16` values is 1.5 `u32` values, so
436 /// that's a failure).
437 /// * Similarly, you can't convert between a [ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts)
438 /// and a non-ZST.
439 #[inline]
try_cast_slice<A: NoUninit, B: AnyBitPattern>( a: &[A], ) -> Result<&[B], PodCastError>440 pub fn try_cast_slice<A: NoUninit, B: AnyBitPattern>(
441 a: &[A],
442 ) -> Result<&[B], PodCastError> {
443 unsafe { internal::try_cast_slice(a) }
444 }
445
446 /// Try to convert `&mut [A]` into `&mut [B]` (possibly with a change in
447 /// length).
448 ///
449 /// As [`try_cast_slice`], but `&mut`.
450 #[inline]
try_cast_slice_mut< A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern, >( a: &mut [A], ) -> Result<&mut [B], PodCastError>451 pub fn try_cast_slice_mut<
452 A: NoUninit + AnyBitPattern,
453 B: NoUninit + AnyBitPattern,
454 >(
455 a: &mut [A],
456 ) -> Result<&mut [B], PodCastError> {
457 unsafe { internal::try_cast_slice_mut(a) }
458 }
459
460 /// Fill all bytes of `target` with zeroes (see [`Zeroable`]).
461 ///
462 /// This is similar to `*target = Zeroable::zeroed()`, but guarantees that any
463 /// padding bytes in `target` are zeroed as well.
464 ///
465 /// See also [`fill_zeroes`], if you have a slice rather than a single value.
466 #[inline]
write_zeroes<T: Zeroable>(target: &mut T)467 pub fn write_zeroes<T: Zeroable>(target: &mut T) {
468 struct EnsureZeroWrite<T>(*mut T);
469 impl<T> Drop for EnsureZeroWrite<T> {
470 #[inline(always)]
471 fn drop(&mut self) {
472 unsafe {
473 core::ptr::write_bytes(self.0, 0u8, 1);
474 }
475 }
476 }
477 unsafe {
478 let guard = EnsureZeroWrite(target);
479 core::ptr::drop_in_place(guard.0);
480 drop(guard);
481 }
482 }
483
484 /// Fill all bytes of `slice` with zeroes (see [`Zeroable`]).
485 ///
486 /// This is similar to `slice.fill(Zeroable::zeroed())`, but guarantees that any
487 /// padding bytes in `slice` are zeroed as well.
488 ///
489 /// See also [`write_zeroes`], which zeroes all bytes of a single value rather
490 /// than a slice.
491 #[inline]
fill_zeroes<T: Zeroable>(slice: &mut [T])492 pub fn fill_zeroes<T: Zeroable>(slice: &mut [T]) {
493 if core::mem::needs_drop::<T>() {
494 // If `T` needs to be dropped then we have to do this one item at a time, in
495 // case one of the intermediate drops does a panic.
496 slice.iter_mut().for_each(write_zeroes);
497 } else {
498 // Otherwise we can be really fast and just fill everthing with zeros.
499 let len = core::mem::size_of_val::<[T]>(slice);
500 unsafe { core::ptr::write_bytes(slice.as_mut_ptr() as *mut u8, 0u8, len) }
501 }
502 }
503