raw_transmute/lib.rs
1//! Rust's own built-in [`transmute`](core::mem::transmute) is, ironically, quite limited.
2//!
3//! It does not support generically-sized types, nor types with different sizes.
4//! This crate provides a more permissive alternative through the use of unions:
5//! - [`raw_transmute`] to unsafely transmute between any two types, regardless of size or
6//! genericity.
7//! - [`raw_transmute_uninit`] to safely transmute into a [`MaybeUninit`] of the destination type.
8//!
9//! The MSRV for this crate is Rust 1.31. However, some features require later versions:
10//! - Transmuting into [`MaybeUninit`] requires Rust 1.36 or later.
11//! - Transmuting for non-[`Copy`] types requires Rust 1.49 or later.
12//! - `const` support for both functions requires Rust 1.56 or later.
13#![no_std]
14
15use ::core::mem::ManuallyDrop;
16
17#[rustversion::since(1.36)]
18use ::core::mem::MaybeUninit;
19
20use ::rustversion;
21
22macro_rules! unionable {
23 ( $($bounds:tt)* ) => {
24 /// Types that can be used as fields of a union.
25 ///
26 /// This always requires [`Sized`]. On Rust < 1.49, it additionally requires [`Copy`].
27 pub trait Unionable: $($bounds)* {}
28
29 impl<T: $($bounds)*> Unionable for T {}
30 };
31}
32
33#[rustversion::since(1.49)]
34unionable! { Sized }
35
36#[rustversion::before(1.49)]
37unionable! { Sized + Copy }
38
39/// A `#[repr(C)]` union used to transmute between types.
40///
41/// This union is used internally by [`raw_transmute`] and [`raw_transmute_uninit`].
42#[repr(C)]
43pub union Transmute<Src: Unionable, Dst: Unionable> {
44 /// The source value.
45 pub src: ManuallyDrop<Src>,
46
47 /// The destination value.
48 pub dst: ManuallyDrop<Dst>,
49}
50
51impl<Src: Copy, Dst: Copy> Clone for Transmute<Src, Dst> {
52 #[inline(always)]
53 fn clone(&self) -> Self {
54 *self
55 }
56}
57
58impl<Src: Copy, Dst: Copy> Copy for Transmute<Src, Dst> {}
59
60/// Transmutes a value of type `Src` into a value of type `Dst` through a union.
61///
62/// This function is more permissive than core's [`transmute`](core::mem::transmute), which does not
63/// work for generically-sized types or types with different sizes. Mind that it is still the
64/// caller's responsibility to ensure that the transmutation is valid! Just like with
65/// [`transmute`](core::mem::transmute), it is undefined behavior to transmute between incompatible
66/// types. Absolutely no checks are performed at runtime nor compile-time!
67///
68/// The behavior of this function is equivalent to the unstable
69/// [`TransmuteFrom::transmute`](core::mem::TransmuteFrom::transmute).
70///
71/// Rust 1.56 stabilized `const` unions, allowing this function to be `const` on 1.56 and later.
72///
73/// # Safety
74///
75/// The current bit pattern of `src` must be valid for the destination type `Dst`. `Src` may have a
76/// different size or alignment than `Dst`: beware of padding bytes, or uninitialized memory
77/// artificially created by size differences that may result from the transmutation.
78///
79/// See [`TransmuteFrom`](core::mem::TransmuteFrom) for more details on what a union-transmute
80/// entails.
81///
82/// ## Example
83///
84/// ```rust
85/// # use raw_transmute::raw_transmute;
86/// #
87/// #[derive(Clone, Copy)]
88/// #[repr(transparent)]
89/// struct Wrapper<T: Copy>(T);
90///
91/// impl<T: Copy> Wrapper<T> {
92/// /// Consumes the wrapper and returns the inner value.
93/// ///
94/// /// This is implemented using [`raw_transmute`].
95/// /// Simply returning `self.0` would fail `const`
96/// /// because the compiler would claim that `self` has to be dropped
97/// /// (unless you turn on the `const_precise_live_drops` unstable feature).
98/// pub const fn into_inner(self) -> T {
99/// // SAFETY: Wrapper<T> is #[repr(transparent)] over T.
100/// unsafe { raw_transmute::<Wrapper<T>, T>(self) }
101/// }
102/// }
103///
104/// let wrapped = Wrapper(42u32);
105/// assert_eq!(wrapped.into_inner(), 42u32);
106/// ```
107///
108/// Using core's [`transmute`](core::mem::transmute) would fail to compile here:
109///
110/// ```rust compile_fail
111/// #[derive(Clone, Copy)]
112/// #[repr(transparent)]
113/// struct Wrapper<T: Copy>(T);
114///
115/// impl<T: Copy> Wrapper<T> {
116/// pub const fn into_inner(self) -> T {
117/// // Fails to compile:
118/// // generically-sized types are not supported by core::mem::transmute.
119/// unsafe { core::mem::transmute::<Wrapper<T>, T>(self) }
120/// }
121/// }
122/// ```
123#[rustversion::attr(since(1.56), const)]
124#[inline(always)]
125pub unsafe fn raw_transmute<Src: Unionable, Dst: Unionable>(src: Src) -> Dst {
126 let transmute = Transmute::<Src, Dst> { src: ManuallyDrop::new(src) };
127
128 ManuallyDrop::into_inner(
129 // SAFETY: Caller's responsibility to ensure Src and Dst can be transmuted.
130 unsafe { transmute.dst },
131 )
132}
133
134/// Transmutes a value of type `Src` into `Dst` wrapped in [`MaybeUninit`].
135///
136/// This is safe because the resulting [`MaybeUninit`] does not require the inner value to be a
137/// valid bit pattern for `Dst`, and can also contain uninitialized memory. It is still the caller's
138/// responsibility to ensure that the resulting [`MaybeUninit`] is used safely.
139///
140/// This version requires Rust 1.36 or later due to the use of [`MaybeUninit`].
141/// Rust 1.56 stabilized `const` unions, allowing this function to be `const` on 1.56 and later.
142///
143/// ## Example
144///
145/// ```rust
146/// # use raw_transmute::raw_transmute_uninit;
147/// #
148/// #[derive(Clone, Copy)]
149/// struct Wrapper<T: Copy>(T);
150///
151/// // Transmute a wrapped u8 into an uninitialized wrapped u64.
152/// //
153/// // Normally, this would be undefined behavior:
154/// // - Wrapper makes no guarantees about its layout.
155/// // Transmuting to a different inner type isn't guaranteed to be valid.
156/// // - Additionally, u8 and u64 have different sizes.
157/// // The resulting value would have uninitialized bytes.
158/// //
159/// // However, since the value is directly transmuted into a `MaybeUninit`,
160/// // the resulting value is allowed to have an invalid bit pattern.
161/// //
162/// // Assuming initialization of this value however, would always be UB!
163/// let _ = raw_transmute_uninit::<Wrapper<u8>, Wrapper<u64>>(Wrapper(0));
164/// ```
165///
166/// Using core's [`transmute`](core::mem::transmute) would fail to compile in this simplified
167/// example (and additionally, requires an unnecessary `unsafe` block):
168///
169/// ```rust compile_fail
170/// # use core::mem::MaybeUninit;
171/// #
172/// let x: u8 = 255;
173///
174/// // Fails to compile:
175/// // u8 and MaybeUninit<u64> have different sizes.
176/// unsafe { core::mem::transmute::<u8, MaybeUninit<u64>>(x) };
177/// ```
178#[rustversion::since(1.36)]
179#[rustversion::attr(since(1.56), const)]
180#[must_use = "transmuting to `MaybeUninit` is useless if the result is not used: `MaybeUninit` inhibits `Dst`'s `Drop`. Consider `forget`?"]
181#[inline(always)]
182pub fn raw_transmute_uninit<Src: Unionable, Dst: Unionable>(src: Src) -> MaybeUninit<Dst> {
183 // SAFETY: Transmuting to MaybeUninit is always safe.
184 unsafe { raw_transmute::<Src, MaybeUninit<Dst>>(src) }
185}