all_is_bytes/
lib.rs

1//! # `all_is_bytes`
2//!
3//! [![crates.io](https://img.shields.io/crates/v/all-is-bytes.svg)](https://crates.io/crates/all-is-bytes)
4//! [![Dependency Status](https://deps.rs/crate/all-is-bytes/0.1.0/status.svg)](https://deps.rs/crate/all-is-bytes/0.1.0)
5//! [![License](https://img.shields.io/badge/license-Unlicense-blue.svg)](https://unlicense.org/)
6//! [![MSRV](https://img.shields.io/badge/MSRV-1.38-white.svg)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field)
7//!
8//! Because everything is just a bunch of bytes... right?
9//!
10//! # See also
11//!
12//! This crate is not very practical to use, as it is for casting **any** type to a byte slice,
13//! regardless of whether or not it contains padding or has interior mutability.
14//! [bytemuck] has mechanisms to *safely* perform such casts, so consider using it instead.
15//!
16//! [bytemuck]: https://crates.io/crates/bytemuck
17
18// Attributes
19#![cfg_attr(not(any(doc, test)), no_std)]
20// Lints
21#![allow(clippy::inline_always)]
22#![deny(
23    clippy::missing_safety_doc,
24    clippy::undocumented_unsafe_blocks,
25    unsafe_op_in_unsafe_fn
26)]
27
28use core::{
29    mem::{self, MaybeUninit},
30    slice,
31};
32
33/// Reinterprets as a byte slice.
34///
35/// Returns <code>&\[[`MaybeUninit`]\<u8\>\]</code> rather than `&[u8]` as it is [undefined behavior] to read padding bytes.
36/// If the type does not contain any padding, it is safe to cast it to `&[u8]` yourself.
37///
38/// # Safety
39///
40/// The type must not have interior mutability.
41///
42/// In other words, the type cannot contain [`Cell`], [`UnsafeCell`], and the like.
43///
44/// ## Why?
45///
46/// Aliasing. See here:
47///
48/// ```no_run
49/// # use core::cell::Cell;
50/// let cell = Cell::new(1u8);
51/// let raw = unsafe { all_is_bytes::cast(&cell) };
52/// cell.set(0u8); // Erm... well that just happened...
53/// assert_eq!(cell.get(), unsafe { raw[0].assume_init() }); // Uh oh!
54/// ```
55///
56/// This causes [undefined behavior].
57///
58/// [`Cell`]: core::cell::Cell
59/// [`UnsafeCell`]: core::cell::UnsafeCell
60/// [undefined behavior]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html
61#[inline(always)]
62#[must_use]
63pub unsafe fn cast<T>(x: &T) -> &[MaybeUninit<u8>]
64where
65    T: ?Sized,
66{
67    let len = mem::size_of_val(x);
68    let ptr = (x as *const T).cast::<MaybeUninit<u8>>();
69
70    // SAFETY: `ptr` is valid and points to a value `len` bytes long.
71    unsafe { slice::from_raw_parts(ptr, len) }
72}
73
74/// Reinterprets as a mutable byte slice.
75///
76/// Returns <code>&\[[`MaybeUninit`]\<u8\>\]</code> rather than `&[u8]` as it is [undefined behavior] to read padding bytes.
77/// If the type does not contain any padding, it is safe to cast it to `&[u8]` yourself.
78///
79/// # Safety
80///
81/// All invariants of the type must be upheld.
82///
83/// ## Why?
84///
85/// See this example with [`NonZeroU8`]:
86///
87/// ```no_run
88/// # use core::num::NonZeroU8;
89/// let mut num = NonZeroU8::new(1).unwrap();
90/// let raw = unsafe { all_is_bytes::cast_mut(&mut num) };
91/// raw[0].write(0); // Don't do this!
92/// ```
93///
94/// As `NonZero*` values must not be 0, this causes [undefined behavior].
95///
96/// References and [`NonNull`] values are similar in that they must not be null.
97///
98/// Additionally, [`str`] has the invariant that its contents must be valid UTF-8.
99/// See [`str::as_bytes_mut`] for more information.
100///
101/// [`NonZeroU8`]: core::num::NonZeroU8
102/// [`NonNull`]: core::ptr::NonNull
103/// [undefined behavior]: https://doc.rust-lang.org/stable/reference/behavior-considered-undefined.html
104#[inline(always)]
105#[must_use]
106pub unsafe fn cast_mut<T>(x: &mut T) -> &mut [MaybeUninit<u8>]
107where
108    T: ?Sized,
109{
110    let len = mem::size_of_val(x);
111    let ptr = (x as *mut T).cast::<MaybeUninit<u8>>();
112
113    // SAFETY: `ptr` is valid and points to a value `len` bytes long.
114    unsafe { slice::from_raw_parts_mut(ptr, len) }
115}