const_serialize/
primitive.rs

1use crate::*;
2use std::mem::MaybeUninit;
3
4/// The layout for a primitive type. The bytes will be reversed if the target is big endian.
5#[derive(Debug, Copy, Clone)]
6pub struct PrimitiveLayout {
7    pub(crate) size: usize,
8}
9
10impl PrimitiveLayout {
11    /// Create a new primitive layout
12    pub const fn new(size: usize) -> Self {
13        Self { size }
14    }
15
16    /// Read the value from the given pointer
17    ///
18    /// # Safety
19    /// The pointer must be valid for reads of `self.size` bytes.
20    pub const unsafe fn read(self, byte_ptr: *const u8) -> u32 {
21        let mut value = 0;
22        let mut offset = 0;
23        while offset < self.size {
24            // If the bytes are reversed, walk backwards from the end of the number when pushing bytes
25            let byte = if cfg!(target_endian = "big") {
26                unsafe {
27                    byte_ptr
28                        .wrapping_byte_add((self.size - offset - 1) as _)
29                        .read()
30                }
31            } else {
32                unsafe { byte_ptr.wrapping_byte_add(offset as _).read() }
33            };
34            value |= (byte as u32) << (offset * 8);
35            offset += 1;
36        }
37        value
38    }
39
40    /// Write the value to the given buffer
41    pub const fn write(self, value: u32, out: &mut [MaybeUninit<u8>]) {
42        let bytes = value.to_ne_bytes();
43        let mut offset = 0;
44        while offset < self.size {
45            out[offset] = MaybeUninit::new(bytes[offset]);
46            offset += 1;
47        }
48    }
49}
50
51macro_rules! impl_serialize_const {
52    ($type:ty) => {
53        unsafe impl SerializeConst for $type {
54            const MEMORY_LAYOUT: Layout = Layout::Primitive(PrimitiveLayout {
55                size: std::mem::size_of::<$type>(),
56            });
57        }
58    };
59}
60
61impl_serialize_const!(u8);
62impl_serialize_const!(u16);
63impl_serialize_const!(u32);
64impl_serialize_const!(u64);
65impl_serialize_const!(i8);
66impl_serialize_const!(i16);
67impl_serialize_const!(i32);
68impl_serialize_const!(i64);
69impl_serialize_const!(bool);
70impl_serialize_const!(f32);
71impl_serialize_const!(f64);
72
73/// Serialize a primitive type that is stored at the pointer passed in
74pub(crate) const unsafe fn serialize_const_primitive(
75    ptr: *const (),
76    to: ConstVec<u8>,
77    layout: &PrimitiveLayout,
78) -> ConstVec<u8> {
79    let ptr = ptr as *const u8;
80    let mut offset = 0;
81    let mut i64_bytes = [0u8; 8];
82    while offset < layout.size {
83        // If the bytes are reversed, walk backwards from the end of the number when pushing bytes
84        let byte = unsafe {
85            if cfg!(any(target_endian = "big", feature = "test-big-endian")) {
86                ptr.wrapping_byte_offset((layout.size - offset - 1) as _)
87                    .read()
88            } else {
89                ptr.wrapping_byte_offset(offset as _).read()
90            }
91        };
92        i64_bytes[offset] = byte;
93        offset += 1;
94    }
95    let number = i64::from_ne_bytes(i64_bytes);
96    write_number(to, number)
97}
98
99/// Deserialize a primitive type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
100pub(crate) const fn deserialize_const_primitive<'a>(
101    from: &'a [u8],
102    layout: &PrimitiveLayout,
103    out: &mut [MaybeUninit<u8>],
104) -> Option<&'a [u8]> {
105    let mut offset = 0;
106    let Ok((number, from)) = take_number(from) else {
107        return None;
108    };
109    let bytes = number.to_le_bytes();
110    while offset < layout.size {
111        // If the bytes are reversed, walk backwards from the end of the number when filling in bytes
112        let byte = bytes[offset];
113        if cfg!(any(target_endian = "big", feature = "test-big-endian")) {
114            out[layout.size - offset - 1] = MaybeUninit::new(byte);
115        } else {
116            out[offset] = MaybeUninit::new(byte);
117        }
118        offset += 1;
119    }
120    Some(from)
121}