micromegas_transit/
serialize.rs

1#[allow(unsafe_code)]
2#[inline(always)]
3pub fn write_any<T>(buffer: &mut Vec<u8>, value: &T) {
4    let ptr = std::ptr::addr_of!(*value).cast::<u8>();
5    let slice = std::ptr::slice_from_raw_parts(ptr, std::mem::size_of::<T>());
6    unsafe {
7        buffer.extend_from_slice(&*slice);
8    }
9}
10
11#[allow(unsafe_code)]
12/// Helper function to read a u* pointer to a value of type T.
13///
14/// # Safety
15/// ptr must be valid it's size and it's memory size must be the size
16/// of T or higher.
17#[inline(always)]
18pub unsafe fn read_any<T>(ptr: *const u8) -> T {
19    unsafe { std::ptr::read_unaligned(ptr.cast::<T>()) }
20}
21
22pub fn advance_window(window: &[u8], offset: usize) -> &[u8] {
23    assert!(offset <= window.len());
24    &window[offset..]
25}
26
27pub fn read_consume_pod<T>(window: &mut &[u8]) -> T {
28    let object_size = std::mem::size_of::<T>();
29    let begin: *const u8 = window.as_ptr();
30    *window = advance_window(window, object_size);
31    unsafe { std::ptr::read_unaligned(begin.cast::<T>()) }
32}
33
34/// Helps speed up the serialization of types which size is known at compile time.
35pub enum InProcSize {
36    Const(usize),
37    Dynamic,
38}
39
40// InProcSerialize is used by the heterogeneous queue to write objects in its
41// buffer serialized objects can have references with static lifetimes
42pub trait InProcSerialize: Sized {
43    const IN_PROC_SIZE: InProcSize = InProcSize::Const(std::mem::size_of::<Self>());
44
45    fn get_value_size(&self) -> Option<u32> {
46        // for POD serialization we don't write the size of each instance
47        // the metadata will contain this size
48        None
49    }
50
51    #[inline(always)]
52    fn write_value(&self, buffer: &mut Vec<u8>) {
53        assert!(matches!(Self::IN_PROC_SIZE, InProcSize::Const(_)));
54        #[allow(clippy::needless_borrow)]
55        //clippy complains here but we don't want to move or copy the value
56        write_any::<Self>(buffer, &self);
57    }
58
59    // read_value allows to read objects from the same process they were stored in
60    // i.e. iterating in the heterogenous queue
61    /// # Safety
62    /// This is called from the serializer context that that uses `value_size`
63    /// call to make sure that the proper size is used
64    #[allow(unsafe_code)]
65    #[inline(always)]
66    unsafe fn read_value(mut window: &[u8]) -> Self {
67        let res = read_consume_pod(&mut window);
68        assert_eq!(window.len(), 0);
69        res
70    }
71}