const_serialize/
struct.rs

1use crate::*;
2
3/// Plain old data for a field. Stores the offset of the field in the struct and the layout of the field.
4#[derive(Debug, Copy, Clone)]
5pub struct StructFieldLayout {
6    name: &'static str,
7    offset: usize,
8    layout: Layout,
9}
10
11impl StructFieldLayout {
12    /// Create a new struct field layout
13    pub const fn new(name: &'static str, offset: usize, layout: Layout) -> Self {
14        Self {
15            name,
16            offset,
17            layout,
18        }
19    }
20}
21
22/// Layout for a struct. The struct layout is just a list of fields with offsets
23#[derive(Debug, Copy, Clone)]
24pub struct StructLayout {
25    pub(crate) size: usize,
26    pub(crate) data: &'static [StructFieldLayout],
27}
28
29impl StructLayout {
30    /// Create a new struct layout
31    pub const fn new(size: usize, data: &'static [StructFieldLayout]) -> Self {
32        Self { size, data }
33    }
34}
35
36/// Serialize a struct that is stored at the pointer passed in
37pub(crate) const unsafe fn serialize_const_struct(
38    ptr: *const (),
39    to: ConstVec<u8>,
40    layout: &StructLayout,
41) -> ConstVec<u8> {
42    let mut i = 0;
43    let field_count = layout.data.len();
44    let mut to = write_map(to, field_count);
45    while i < field_count {
46        // Serialize the field at the offset pointer in the struct
47        let StructFieldLayout {
48            name,
49            offset,
50            layout,
51        } = &layout.data[i];
52        to = write_map_key(to, name);
53        let field = ptr.wrapping_byte_add(*offset as _);
54        to = serialize_const_ptr(field, to, layout);
55        i += 1;
56    }
57    to
58}
59
60/// Deserialize a struct type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
61pub(crate) const fn deserialize_const_struct<'a>(
62    from: &'a [u8],
63    layout: &StructLayout,
64    out: &mut [MaybeUninit<u8>],
65) -> Option<&'a [u8]> {
66    let Ok((map, from)) = take_map(from) else {
67        return None;
68    };
69    let mut i = 0;
70    while i < layout.data.len() {
71        // Deserialize the field at the offset pointer in the struct
72        let StructFieldLayout {
73            name,
74            offset,
75            layout,
76        } = &layout.data[i];
77        let Ok(Some(from)) = map.find(name) else {
78            return None;
79        };
80        let Some((_, field_bytes)) = out.split_at_mut_checked(*offset) else {
81            return None;
82        };
83        if deserialize_const_ptr(from, layout, field_bytes).is_none() {
84            return None;
85        }
86        i += 1;
87    }
88    Some(from)
89}
90
91macro_rules! impl_serialize_const_tuple {
92    ($($generic:ident: $generic_number:expr),*) => {
93        impl_serialize_const_tuple!(@impl ($($generic,)*) = $($generic: $generic_number),*);
94    };
95    (@impl $inner:ty = $($generic:ident: $generic_number:expr),*) => {
96        unsafe impl<$($generic: SerializeConst),*> SerializeConst for ($($generic,)*) {
97            const MEMORY_LAYOUT: Layout = {
98                Layout::Struct(StructLayout {
99                    size: std::mem::size_of::<($($generic,)*)>(),
100                    data: &[
101                        $(
102                            StructFieldLayout::new(stringify!($generic_number), std::mem::offset_of!($inner, $generic_number), $generic::MEMORY_LAYOUT),
103                        )*
104                    ],
105                })
106            };
107        }
108    };
109}
110
111impl_serialize_const_tuple!(T1: 0);
112impl_serialize_const_tuple!(T1: 0, T2: 1);
113impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2);
114impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3);
115impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4);
116impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5);
117impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6);
118impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7);
119impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7, T9: 8);
120impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7, T9: 8, T10: 9);