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
/*
 * SPDX-FileCopyrightText: 2023 Inria
 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
 *
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
 */

/*!

Traits computing information about a type.

*/

use crate::pad_align_to;
use core::hash::Hash;

/// Recursively compute a type hash for a type.
///
/// [`TypeHash::type_hash`] is a recursive function that computes information
/// about a type. It is used to
/// check that the type of the data being deserialized matches
/// syntactically the type of the data that was written.
///
/// The type hasher should store information about the name and the type
/// of the fields of a type, and the name of the type itself.
pub trait TypeHash {
    /// Accumulate type information in `hasher`.
    fn type_hash(hasher: &mut impl core::hash::Hasher);

    /// Call [`TypeHash::type_hash`] on a value.
    fn type_hash_val(&self, hasher: &mut impl core::hash::Hasher) {
        Self::type_hash(hasher);
    }
}

/// Recursively compute a representational hash for a type.
///
/// [`ReprHash::repr_hash`] is a recursive function that computes
/// representation information about a zero-copy type. It is used to
/// check that the the alignment and the representation data
/// of the data being deserialized.
///
/// More precisely, at each call a zero-copy type look at `offset_of`,
/// assuming that the type is stored at that offset in the structure,
/// hashes in the padding necessary to make `offset_of` a multiple of
/// [`core::mem::align_of`] the type, hashes in the type size, and
/// finally increases `offset_of` by [`core::mem::size_of`] the type.
pub trait ReprHash {
    /// Accumulate representional information in `hasher` assuming to
    /// be positioned at `offset_of`.
    fn repr_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize);

    /// Call [`ReprHash::repr_hash`] on a value.
    fn repr_hash_val(&self, hasher: &mut impl core::hash::Hasher, offset_of: &mut usize) {
        Self::repr_hash(hasher, offset_of);
    }
}

/// A function providing a reasonable default
/// implementation of [`ReprHash::repr_hash`] for basic sized types.
pub(crate) fn std_repr_hash<T>(hasher: &mut impl core::hash::Hasher, offset_of: &mut usize) {
    let padding = pad_align_to(*offset_of, core::mem::align_of::<T>());
    padding.hash(hasher);
    core::mem::size_of::<T>().hash(hasher);
    *offset_of += padding;
    *offset_of += core::mem::size_of::<T>();
}

/// A trait providing the maximum size of a primitive field in a type
/// maximized with [`core::mem::align_of`].
///
/// We use the value returned by [`MaxSizeOf::max_size_of`]
/// to generate padding before storing a zero-copy type. Note that this
/// is different from the padding used to align the same type inside
/// a struct, which is not under our control and is
/// given by [`core::mem::align_of`].
///
/// In this way we increase interoperability between architectures
/// with different alignment requirements for the same types (e.g.,
/// 4 or 8 bytes for `u64`).
///
/// By maximizing with [`core::mem::align_of`] we ensure that
/// we provide sufficient alignment in case the attribute `repr(align(N))`
/// was specified.
pub trait MaxSizeOf: Sized {
    fn max_size_of() -> usize;
}