Skip to main content

yog_mirror/
cell.rs

1//! What a column holds a row of: a fixed-width value, little-endian, the
2//! same bytes Java reads ([`Kind`] and a count describe it to both sides).
3
4/// The number a cell is made of.
5#[repr(u8)]
6#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
7pub enum Kind {
8    U8,
9    I32,
10    U32,
11    I64,
12    U64,
13    F32,
14    F64,
15}
16
17impl Kind {
18    /// Bytes one takes.
19    pub const fn size(self) -> usize {
20        match self {
21            Kind::U8 => 1,
22            Kind::I32 | Kind::U32 | Kind::F32 => 4,
23            Kind::I64 | Kind::U64 | Kind::F64 => 8,
24        }
25    }
26
27    /// Its number on the wire (what [`Kind::from_code`] reads back).
28    pub const fn code(self) -> u8 {
29        self as u8
30    }
31
32    pub const fn from_code(code: u8) -> Option<Kind> {
33        Some(match code {
34            0 => Kind::U8,
35            1 => Kind::I32,
36            2 => Kind::U32,
37            3 => Kind::I64,
38            4 => Kind::U64,
39            5 => Kind::F32,
40            6 => Kind::F64,
41            _ => return None,
42        })
43    }
44}
45
46/// A column's row: `COUNT` numbers of one [`Kind`].
47pub trait Cell: Copy + Default + 'static {
48    const KIND: Kind;
49    const COUNT: u32;
50    /// Bytes a row.
51    const WIDTH: usize = Self::KIND.size() * Self::COUNT as usize;
52    /// Writes itself into `out` (`WIDTH` bytes).
53    fn put(&self, out: &mut [u8]);
54    /// Reads one back from `bytes` (`WIDTH` bytes).
55    fn take(bytes: &[u8]) -> Self;
56}
57
58macro_rules! numbers {
59    ($($t:ty => $kind:ident),* $(,)?) => {$(
60        impl Cell for $t {
61            const KIND: Kind = Kind::$kind;
62            const COUNT: u32 = 1;
63            #[inline]
64            fn put(&self, out: &mut [u8]) {
65                out[..Self::WIDTH].copy_from_slice(&self.to_le_bytes());
66            }
67            #[inline]
68            fn take(bytes: &[u8]) -> Self {
69                let mut b = [0u8; std::mem::size_of::<$t>()];
70                b.copy_from_slice(&bytes[..Self::WIDTH]);
71                <$t>::from_le_bytes(b)
72            }
73        }
74    )*};
75}
76
77numbers!(u8 => U8, i32 => I32, u32 => U32, i64 => I64, u64 => U64, f32 => F32, f64 => F64);
78
79impl Cell for bool {
80    const KIND: Kind = Kind::U8;
81    const COUNT: u32 = 1;
82    #[inline]
83    fn put(&self, out: &mut [u8]) {
84        out[0] = u8::from(*self);
85    }
86    #[inline]
87    fn take(bytes: &[u8]) -> Self {
88        bytes[0] != 0
89    }
90}
91
92impl<T: Cell, const N: usize> Cell for [T; N]
93where
94    [T; N]: Default,
95{
96    const KIND: Kind = T::KIND;
97    const COUNT: u32 = T::COUNT * N as u32;
98    #[inline]
99    fn put(&self, out: &mut [u8]) {
100        let out = &mut out[..Self::WIDTH];
101        for (i, v) in self.iter().enumerate() {
102            v.put(&mut out[i * T::WIDTH..]);
103        }
104    }
105    #[inline]
106    fn take(bytes: &[u8]) -> Self {
107        let bytes = &bytes[..Self::WIDTH];
108        std::array::from_fn(|i| T::take(&bytes[i * T::WIDTH..]))
109    }
110}
111
112/// A cell holding no atom.
113pub const NO_ATOM: u32 = u32::MAX;
114
115/// An atom (a name kept once a process: an entity type, a dimension) as
116/// its number; [`NO_ATOM`] for none.
117impl Cell for Option<yog_data::Atom> {
118    const KIND: Kind = Kind::U32;
119    const COUNT: u32 = 1;
120
121    #[inline]
122    fn put(&self, out: &mut [u8]) {
123        self.map_or(NO_ATOM, yog_data::Atom::number).put(out);
124    }
125
126    #[inline]
127    fn take(bytes: &[u8]) -> Self {
128        match u32::take(bytes) {
129            NO_ATOM => None,
130            n => yog_data::Atom::from_number(n),
131        }
132    }
133}