1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * SPDX-FileCopyrightText: 2023 Inria
 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
 *
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
 */

/*!

Helpers for serialization.

*/

use super::{SerializeInner, WriteWithNames};
use crate::ser;
use crate::traits::*;

pub fn check_zero_copy<V: SerializeInner>() {
    if !V::IS_ZERO_COPY {
        panic!(
            "Cannot serialize type {} declared as zero-copy as it is not zero-copy",
            core::any::type_name::<V>()
        );
    }
}

/// Serialize a zero-copy structure by writing its bytes properly [aligned](WriteWithNames::align).
///
/// Note that this method uses a single `write_all` call to write the entire structure.
///
/// Here we check [that the type is actually zero-copy](SerializeInner::IS_ZERO_COPY).
pub fn serialize_zero<V: ZeroCopy + SerializeInner>(
    backend: &mut impl WriteWithNames,
    value: &V,
) -> ser::Result<()> {
    check_zero_copy::<V>();
    let buffer = unsafe {
        #[allow(clippy::manual_slice_size_calculation)]
        core::slice::from_raw_parts(value as *const V as *const u8, core::mem::size_of::<V>())
    };
    backend.align::<V>()?;
    backend.write_bytes::<V>(buffer)
}

/// Serialize a slice of zero-copy structures by encoding
/// its length first, and then its bytes properly [aligned](WriteWithNames::align).
///
/// Note that this method uses a single `write_all`
/// call to write the entire slice.
///
/// Here we check [that the type is actually zero-copy](SerializeInner::IS_ZERO_COPY).
pub fn serialize_slice_zero<V: SerializeInner + ZeroCopy>(
    backend: &mut impl WriteWithNames,
    data: &[V],
) -> ser::Result<()> {
    check_zero_copy::<V>();

    let len = data.len();
    backend.write("len", &len)?;
    let buffer = unsafe {
        #[allow(clippy::manual_slice_size_calculation)]
        core::slice::from_raw_parts(data.as_ptr() as *const u8, len * core::mem::size_of::<V>())
    };
    backend.align::<V>()?;
    backend.write_bytes::<V>(buffer)
}

pub fn check_mismatch<V: SerializeInner>() {
    if V::ZERO_COPY_MISMATCH {
        eprintln!("Type {} is zero-copy, but it has not declared as such; use the #[deep_copy] attribute to silence this warning", core::any::type_name::<V>());
    }
}

/// Serialize a slice of deep-copy structures by encoding
/// its length first, and then the contents item by item.
///
/// Here we warn [that the type might actually be zero-copy](SerializeInner::ZERO_COPY_MISMATCH).
pub fn serialize_slice_deep<V: SerializeInner>(
    backend: &mut impl WriteWithNames,
    data: &[V],
) -> ser::Result<()> {
    check_mismatch::<V>();
    let len = data.len();
    backend.write("len", &len)?;
    for item in data.iter() {
        backend.write("item", item)?;
    }
    Ok(())
}