Skip to main content

as_repr_core/
lib.rs

1//! Rust trait for constant #[repr(T)] conversions.
2
3#![doc(
4    html_logo_url = "https://ardaku.github.io/mm/logo.svg",
5    html_favicon_url = "https://ardaku.github.io/mm/icon.svg"
6)]
7#![no_std]
8#![warn(
9    anonymous_parameters,
10    missing_copy_implementations,
11    missing_debug_implementations,
12    missing_docs,
13    nonstandard_style,
14    rust_2018_idioms,
15    single_use_lifetimes,
16    trivial_casts,
17    trivial_numeric_casts,
18    unreachable_pub,
19    unused_extern_crates,
20    unused_qualifications,
21    variant_size_differences
22)]
23#![deny(
24    rustdoc::broken_intra_doc_links,
25    rustdoc::private_intra_doc_links,
26    rustdoc::missing_crate_level_docs,
27    rustdoc::private_doc_tests,
28    rustdoc::invalid_codeblock_attributes,
29    rustdoc::invalid_html_tags,
30    rustdoc::invalid_rust_codeblocks,
31    rustdoc::bare_urls,
32    rustdoc::unescaped_backticks,
33    rustdoc::redundant_explicit_links
34)]
35
36#[cfg(feature = "cmp")]
37pub mod cmp;
38#[cfg(feature = "float")]
39pub mod float;
40#[cfg(feature = "inherent")]
41pub mod inherent;
42#[cfg(feature = "int")]
43pub mod int;
44#[cfg(feature = "num")]
45pub mod num;
46#[cfg(feature = "ops")]
47pub mod ops;
48
49use core::{
50    mem::{self, ManuallyDrop},
51    num::{
52        NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
53        NonZeroIsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64,
54        NonZeroU128, NonZeroUsize,
55    },
56    ptr::NonNull,
57};
58
59/// Trait that allows usage with [`as_repr()`]
60///
61/// # Safety
62///
63///  - For this trait to be safe to implement, it must be `#[repr(T)]`
64pub unsafe trait AsRepr<T> {}
65
66// unsafe: all types `#[repr]` themselves
67unsafe impl<T> AsRepr<T> for T {}
68
69// unsafe: `[T; 1]` and `[T]` have the same repr
70unsafe impl<T> AsRepr<[T; 1]> for T {}
71unsafe impl<T> AsRepr<T> for [T; 1] {}
72unsafe impl<T> AsRepr<[[T; 1]; 1]> for T {}
73unsafe impl<T> AsRepr<T> for [[T; 1]; 1] {}
74unsafe impl<T> AsRepr<[[[T; 1]; 1]; 1]> for T {}
75unsafe impl<T> AsRepr<T> for [[[T; 1]; 1]; 1] {}
76unsafe impl<T> AsRepr<[[[[T; 1]; 1]; 1]; 1]> for T {}
77unsafe impl<T> AsRepr<T> for [[[[T; 1]; 1]; 1]; 1] {}
78
79// unsafe: `NonZero<T>` guaranteed to have the same layout and bit validity as T
80// with the exception that that the all-zero bit pattern is invalid
81// <https://doc.rust-lang.org/std/num/struct.NonZero.html#layout-1>
82unsafe impl AsRepr<u8> for NonZeroU8 {}
83unsafe impl AsRepr<u16> for NonZeroU16 {}
84unsafe impl AsRepr<u32> for NonZeroU32 {}
85unsafe impl AsRepr<u64> for NonZeroU64 {}
86unsafe impl AsRepr<u128> for NonZeroU128 {}
87unsafe impl AsRepr<usize> for NonZeroUsize {}
88unsafe impl AsRepr<i8> for NonZeroI8 {}
89unsafe impl AsRepr<i16> for NonZeroI16 {}
90unsafe impl AsRepr<i32> for NonZeroI32 {}
91unsafe impl AsRepr<i64> for NonZeroI64 {}
92unsafe impl AsRepr<i128> for NonZeroI128 {}
93unsafe impl AsRepr<isize> for NonZeroIsize {}
94
95// unsafe: `Option<NonZero<T>>` is guaranteed to be compatible with `T`,
96// including in FFI
97// <https://doc.rust-lang.org/std/num/struct.NonZero.html#layout-1>
98unsafe impl AsRepr<u8> for Option<NonZeroU8> {}
99unsafe impl AsRepr<u16> for Option<NonZeroU16> {}
100unsafe impl AsRepr<u32> for Option<NonZeroU32> {}
101unsafe impl AsRepr<u64> for Option<NonZeroU64> {}
102unsafe impl AsRepr<u128> for Option<NonZeroU128> {}
103unsafe impl AsRepr<usize> for Option<NonZeroUsize> {}
104unsafe impl AsRepr<i8> for Option<NonZeroI8> {}
105unsafe impl AsRepr<i16> for Option<NonZeroI16> {}
106unsafe impl AsRepr<i32> for Option<NonZeroI32> {}
107unsafe impl AsRepr<i64> for Option<NonZeroI64> {}
108unsafe impl AsRepr<i128> for Option<NonZeroI128> {}
109unsafe impl AsRepr<isize> for Option<NonZeroIsize> {}
110unsafe impl AsRepr<Option<NonZeroU8>> for u8 {}
111unsafe impl AsRepr<Option<NonZeroU16>> for u16 {}
112unsafe impl AsRepr<Option<NonZeroU32>> for u32 {}
113unsafe impl AsRepr<Option<NonZeroU64>> for u64 {}
114unsafe impl AsRepr<Option<NonZeroU128>> for u128 {}
115unsafe impl AsRepr<Option<NonZeroUsize>> for usize {}
116unsafe impl AsRepr<Option<NonZeroI8>> for i8 {}
117unsafe impl AsRepr<Option<NonZeroI16>> for i16 {}
118unsafe impl AsRepr<Option<NonZeroI32>> for i32 {}
119unsafe impl AsRepr<Option<NonZeroI64>> for i64 {}
120unsafe impl AsRepr<Option<NonZeroI128>> for i128 {}
121unsafe impl AsRepr<Option<NonZeroIsize>> for isize {}
122
123// unsafe: `Self::NonZeroInner` to `Option<Self::NonZeroInner>` transmute is
124// sound
125// <https://doc.rust-lang.org/std/num/trait.ZeroablePrimitive.html#safety>
126unsafe impl AsRepr<Option<NonZeroU8>> for NonZeroU8 {}
127unsafe impl AsRepr<Option<NonZeroU16>> for NonZeroU16 {}
128unsafe impl AsRepr<Option<NonZeroU32>> for NonZeroU32 {}
129unsafe impl AsRepr<Option<NonZeroU64>> for NonZeroU64 {}
130unsafe impl AsRepr<Option<NonZeroU128>> for NonZeroU128 {}
131unsafe impl AsRepr<Option<NonZeroUsize>> for NonZeroUsize {}
132unsafe impl AsRepr<Option<NonZeroI8>> for NonZeroI8 {}
133unsafe impl AsRepr<Option<NonZeroI16>> for NonZeroI16 {}
134unsafe impl AsRepr<Option<NonZeroI32>> for NonZeroI32 {}
135unsafe impl AsRepr<Option<NonZeroI64>> for NonZeroI64 {}
136unsafe impl AsRepr<Option<NonZeroI128>> for NonZeroI128 {}
137unsafe impl AsRepr<Option<NonZeroIsize>> for NonZeroIsize {}
138
139// unsafe: Mutable references can be coerced to immutable
140unsafe impl<T, U> AsRepr<&T> for &mut U where U: AsRepr<T> + Sized {}
141unsafe impl<T, U> AsRepr<Option<&T>> for Option<&mut U> where
142    U: AsRepr<T> + Sized
143{
144}
145
146// unsafe: References to sized types have the same representation as pointers
147unsafe impl<T, U> AsRepr<*mut T> for &U where U: AsRepr<T> + Sized {}
148unsafe impl<T, U> AsRepr<*const T> for &U where U: AsRepr<T> + Sized {}
149unsafe impl<T, U> AsRepr<NonNull<T>> for &U where U: AsRepr<T> + Sized {}
150unsafe impl<T, U> AsRepr<Option<NonNull<T>>> for &U where U: AsRepr<T> + Sized {}
151unsafe impl<T, U> AsRepr<*mut T> for &mut U where U: AsRepr<T> + Sized {}
152unsafe impl<T, U> AsRepr<*const T> for &mut U where U: AsRepr<T> + Sized {}
153unsafe impl<T, U> AsRepr<NonNull<T>> for &mut U where U: AsRepr<T> + Sized {}
154unsafe impl<T, U> AsRepr<Option<NonNull<T>>> for &mut U where
155    U: AsRepr<T> + Sized
156{
157}
158
159// unsafe: Optional references to sized types have the same representation as
160// pointers
161// <https://doc.rust-lang.org/std/primitive.reference.html>
162unsafe impl<T, U> AsRepr<*mut T> for Option<&U> where U: AsRepr<T> + Sized {}
163unsafe impl<T, U> AsRepr<*const T> for Option<&U> where U: AsRepr<T> + Sized {}
164unsafe impl<T, U> AsRepr<Option<NonNull<T>>> for Option<&U> where
165    U: AsRepr<T> + Sized
166{
167}
168unsafe impl<T, U> AsRepr<*mut T> for Option<&mut U> where U: AsRepr<T> + Sized {}
169unsafe impl<T, U> AsRepr<*const T> for Option<&mut U> where U: AsRepr<T> + Sized {}
170unsafe impl<T, U> AsRepr<Option<NonNull<T>>> for Option<&mut U> where
171    U: AsRepr<T> + Sized
172{
173}
174
175// unsafe: `NonNull<T>` to `Option<NonNull<T>>` transmute is sound
176// <https://doc.rust-lang.org/std/ptr/struct.NonNull.html#representation>
177unsafe impl<T, U> AsRepr<Option<NonNull<T>>> for NonNull<U> where
178    U: AsRepr<T> + Sized
179{
180}
181
182// unsafe: `Option<NonNull<T>>` has the same layout as `*const T` and `*mut T`
183// https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.as_ptr
184unsafe impl<T, U> AsRepr<*mut T> for Option<NonNull<U>> where
185    U: AsRepr<T> + Sized
186{
187}
188unsafe impl<T, U> AsRepr<*const T> for Option<NonNull<U>> where
189    U: AsRepr<T> + Sized
190{
191}
192
193// unsafe: floats are represented in bits as unsigned integers
194// <https://doc.rust-lang.org/std/primitive.f32.html#method.from_bits>
195unsafe impl AsRepr<u32> for f32 {}
196unsafe impl AsRepr<u64> for f64 {}
197
198// unsafe: `usize` is pointer sized (although without provenance, which is why
199// this is only safe one way)
200unsafe impl<T> AsRepr<usize> for *mut T where T: Sized {}
201unsafe impl<T> AsRepr<usize> for *const T where T: Sized {}
202unsafe impl<T> AsRepr<usize> for NonNull<T> where T: Sized {}
203unsafe impl<T> AsRepr<usize> for Option<NonNull<T>> where T: Sized {}
204
205// unsafe: `*mut T`, `*const T` and `NonNull<T>` have the same representation
206unsafe impl<T, U> AsRepr<*const T> for *mut U where U: AsRepr<T> + Sized {}
207unsafe impl<T, U> AsRepr<Option<NonNull<T>>> for *mut U where
208    U: AsRepr<T> + Sized
209{
210}
211unsafe impl<T, U> AsRepr<*mut T> for *const U where U: AsRepr<T> + Sized {}
212unsafe impl<T, U> AsRepr<Option<NonNull<T>>> for *const U where
213    U: AsRepr<T> + Sized
214{
215}
216unsafe impl<T, U> AsRepr<*const T> for NonNull<U> where U: AsRepr<T> + Sized {}
217unsafe impl<T, U> AsRepr<*mut T> for NonNull<U> where U: AsRepr<T> + Sized {}
218
219/// Convert a type implementing [`AsRepr`] to `T`.
220///
221/// # Example
222///
223/// Types and arrays of size one have the same representation.
224///
225/// ```rust
226/// # use as_repr_core as as_repr;
227/// assert_eq!(as_repr::as_repr::<[u32; 1]>(4u32), [4u32]);
228/// assert_eq!(as_repr::as_repr::<u32>([4u32]), 4u32);
229///
230/// assert_eq!(as_repr::as_repr::<[[u32; 1]; 1]>(4u32), [[4u32]]);
231/// assert_eq!(as_repr::as_repr::<u32>([[4u32]]), 4u32);
232///
233/// assert_eq!(as_repr::as_repr::<[[u32; 1]; 1]>([4u32]), [[4u32]]);
234/// assert_eq!(as_repr::as_repr::<[u32; 1]>([[4u32]]), [4u32]);
235/// ```
236pub const fn as_repr<T>(value: impl AsRepr<T>) -> T {
237    let value = ManuallyDrop::new(value);
238
239    // safety: not calling drop allows us to move the data with a "copy"
240    unsafe { mem::transmute_copy(&value) }
241}
242
243/// Convert a reference to type implementing [`AsRepr`] to `&T`.
244///
245/// # Example
246///
247/// Types and arrays of size one have the same representation.
248///
249/// ```rust
250/// # use as_repr_core as as_repr;
251/// let a: &u32 = &42;
252/// let b: &[u32; 1] = &[42];
253///
254/// assert_eq!(as_repr::as_repr_ref::<[u32; 1]>(a), b);
255/// ```
256pub const fn as_repr_ref<T>(value: &impl AsRepr<T>) -> &T {
257    unsafe { mem::transmute(value) }
258}
259
260/// Convert a slice of a type implementing [`AsRepr`] to `&[T]`.
261///
262/// # Example
263///
264/// Types and arrays of size one have the same representation.
265///
266/// ```rust
267/// # use as_repr_core as as_repr;
268/// let a: &[u32] = &[1, 2, 3];
269/// let b: &[[u32; 1]] = &[[1], [2], [3]];
270///
271/// assert_eq!(as_repr::as_repr_slice::<[u32; 1]>(a), b);
272/// ```
273pub const fn as_repr_slice<T>(value: &[impl AsRepr<T>]) -> &[T] {
274    unsafe { mem::transmute(value) }
275}