lazy_bytes_cast/
convert.rs

1use core::{mem, ptr, marker};
2
3use crate::read::Out;
4
5const unsafe fn transmute_slice<IN, OUT>(val: &IN) -> &[OUT] {
6    &*ptr::slice_from_raw_parts(val as *const IN as *const OUT, mem::size_of::<IN>())
7}
8
9unsafe fn transmute_slice_mut<IN, OUT>(val: &mut IN) -> &mut [OUT] {
10    &mut *ptr::slice_from_raw_parts_mut(val as *mut IN as *mut OUT, mem::size_of::<IN>())
11}
12
13const unsafe fn transmute_ref<IN, OUT: Copy>(val: &IN) -> OUT {
14    *(mem::transmute::<_, &mem::MaybeUninit<OUT>>(val).assume_init_ref())
15}
16
17///Marker indicating that it is plain old data.
18pub unsafe trait Pod: Copy {
19}
20
21macro_rules! impl_pod {
22    ($($ty:ident),*) => {$(
23        unsafe impl Pod for $ty {
24        }
25    )*};
26}
27
28impl_pod!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);
29unsafe impl<T: Pod> Pod for mem::ManuallyDrop<T> {
30}
31
32struct Validator<IN, OUT> {
33    _result: marker::PhantomData<(IN, OUT)>,
34}
35
36impl<IN, OUT: Copy> Validator<IN, OUT> {
37    const IS_NOT_ZST: () = {
38        assert!(mem::size_of::<IN>() > 0);
39        assert!(mem::size_of::<OUT>() > 0);
40    };
41
42    const IS_SAME_SIZE: () = {
43        assert!(mem::size_of::<IN>() == mem::size_of::<OUT>());
44    };
45
46    const IS_ENOUGH_BYTES: () = {
47        assert!(mem::size_of::<IN>() >= mem::size_of::<OUT>());
48    };
49}
50
51#[inline]
52///Gets uninit byte slice out of the type.
53///
54///Because type of any size can be safely represented as slice of uninitialized bytes, this method is safe to use.
55///It is up to user to interpret result correctly and safe.
56///
57///## Usage
58///
59///```
60///use lazy_bytes_cast::uninit_byte_slice_from;
61///use core::mem::MaybeUninit;
62///
63///static BYTES: &[MaybeUninit<u8>] = uninit_byte_slice_from(&0u32);
64///```
65///
66///## Restrictions
67///
68///Compilation fails for ZST.
69///
70///```compile_fail
71///use lazy_bytes_cast::uninit_byte_slice_from;
72///use core::mem::MaybeUninit;
73///
74///static BYTES: &[MaybeUninit<u8>] = uninit_byte_slice_from(&());
75///```
76pub const fn uninit_byte_slice_from<T>(val: &T) -> &[mem::MaybeUninit<u8>] {
77    let _ = Validator::<T, &[u8]>::IS_NOT_ZST;
78    unsafe {
79        transmute_slice(val)
80    }
81}
82
83#[inline]
84///Gets mutable uninit byte slice out of the type.
85///
86///It is up to user to interpret result correctly and safe.
87///
88///## Usage
89///
90///```
91///use lazy_bytes_cast::uninit_byte_slice_mut_from;
92///
93///let bytes = unsafe {
94///    uninit_byte_slice_mut_from(&mut 0u32)
95///};
96///```
97pub unsafe fn uninit_byte_slice_mut_from<T>(val: &mut T) -> &mut [mem::MaybeUninit<u8>] {
98    let _ = Validator::<T, &[u8]>::IS_NOT_ZST;
99    unsafe {
100        transmute_slice_mut(val)
101    }
102}
103
104#[inline]
105///Gets byte slice out of the type.
106///
107///Available only for types that marked as `Pod`.
108///
109///## Usage
110///
111///```
112///use lazy_bytes_cast::byte_slice_from;
113///
114///static BYTES: &[u8] = byte_slice_from(&0u32);
115///```
116///
117///## Restrictions
118///
119///Compilation fails for invalid type.
120///
121///```compile_fail
122///use lazy_bytes_cast::byte_slice_from;
123///
124///static BYTES: &[u8] = byte_slice_from(&());
125///```
126pub const fn byte_slice_from<T: Pod>(val: &T) -> &[u8] {
127    let _ = Validator::<T, &[u8]>::IS_NOT_ZST;
128    unsafe {
129        transmute_slice(val)
130    }
131}
132
133#[inline]
134///Gets mutable byte slice out of the type.
135///
136///Available only for types that marked as `Pod`.
137///
138///## Usage
139///
140///```
141///use lazy_bytes_cast::byte_slice_mut_from;
142///
143///let bytes = byte_slice_mut_from(&mut 0u32);
144///```
145///
146///## Restrictions
147///
148///Compilation fails for invalid type.
149///
150///```compile_fail
151///use lazy_bytes_cast::byte_slice_mut_from;
152///
153///let bytes = byte_slice_mut_from(&mut ());
154///```
155pub fn byte_slice_mut_from<T: Pod>(val: &mut T) -> &mut [u8] {
156    let _ = Validator::<T, &[u8]>::IS_NOT_ZST;
157    unsafe {
158        transmute_slice_mut(val)
159    }
160}
161
162#[inline]
163///Reads `N` bytes from `Pod` object by performing `memcpy`
164///
165///## Usage
166///
167///```
168///use lazy_bytes_cast::to_bytes;
169///
170///const INPUT: [u8; 4] = [123, 25, 99, 250];
171///static BYTES: [u8; 4] = to_bytes(&u32::from_ne_bytes(INPUT));
172///assert_eq!(BYTES, INPUT);
173///
174///static HALF: [u8; 2] = to_bytes(&u32::from_ne_bytes(INPUT));
175///assert_eq!(HALF, &INPUT[..2]);
176///```
177///
178///## Restrictions
179///
180///Compilation fails if `val` doesn't have enough bytes to read from.
181///
182///```compile_fail
183///use lazy_bytes_cast::to_bytes;
184///
185///static BYTES: [u8; 5] = to_bytes(&0u32);
186///```
187pub const fn to_bytes<T: Pod, const N: usize>(val: &T) -> [u8; N] {
188    let _ = Validator::<T, [u8; N]>::IS_ENOUGH_BYTES;
189    unsafe {
190        transmute_ref(val)
191    }
192}
193
194#[inline]
195///Reads `N` bytes from `Pod` object by performing `memcpy`
196///
197///## Usage
198///
199///```
200///use lazy_bytes_cast::from_bytes;
201///
202///const INPUT: u32 = 500_900_100;
203///const RES: u32 = from_bytes(&INPUT.to_ne_bytes());
204///assert_eq!(RES, INPUT);
205///```
206///
207///## Restrictions
208///
209///Compilation fails if `val` is not the same size as output.
210///
211///```compile_fail,ignore
212///use lazy_bytes_cast::from_bytes;
213///
214///let res: u32 = from_bytes(&[1, 2, 3]);
215///```
216pub const fn from_bytes<T: Pod, const N: usize>(val: &[u8; N]) -> T {
217    let _ = Validator::<[u8; N], T>::IS_SAME_SIZE;
218    unsafe {
219        (*(val.as_ptr() as *const Out<T>)).0
220    }
221}