blackbox_log/parser/decode/
mod.rs

1#![allow(clippy::cast_possible_truncation)]
2
3mod negative_14_bit;
4mod tagged_16;
5mod tagged_32;
6mod tagged_variable;
7mod variable;
8
9use alloc::vec::Vec;
10
11pub(crate) use self::negative_14_bit::negative_14_bit;
12pub(crate) use self::tagged_16::tagged_16;
13pub(crate) use self::tagged_32::tagged_32;
14pub(crate) use self::tagged_variable::tagged_variable;
15pub(crate) use self::variable::{variable, variable_signed};
16use super::InternalResult;
17use crate::Reader;
18
19byte_enum! {
20    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
21    #[repr(u8)]
22    pub(crate) enum Encoding {
23        /// Signed variable byte
24        VariableSigned = 0,
25        /// Unsigned variable byte
26        Variable = 1,
27        /// Unsigned variable byte, but negated after decoding. Value fits in 14
28        /// bits
29        Negative14Bit = 3,
30        TaggedVariable = 6,
31        Tagged32 = 7,
32        /// 1 tag byte containing 4 2 bit tags, followed by 4 fields
33        ///
34        /// | Tag | Field width         |
35        /// |-----|---------------------|
36        /// | 0   | 0 (field value = 0) |
37        /// | 1   | 4                   |
38        /// | 2   | 8                   |
39        /// | 3   | 16                  |
40        Tagged16 = 8,
41        /// Nothing is written to the log, assume value is 0
42        Null = 9,
43    }
44}
45
46impl Encoding {
47    pub(crate) const fn is_signed(&self) -> bool {
48        match self {
49            Self::VariableSigned
50            | Self::Negative14Bit
51            | Self::TaggedVariable
52            | Self::Tagged32
53            | Self::Tagged16 => true,
54            Self::Variable | Self::Null => false,
55        }
56    }
57
58    pub(crate) const fn max_chunk_size(&self) -> usize {
59        match self {
60            Self::TaggedVariable => 8,
61            Self::Tagged32 => 3,
62            Self::Tagged16 => 4,
63            Self::VariableSigned | Self::Variable | Self::Negative14Bit | Self::Null => 1,
64        }
65    }
66
67    pub(crate) fn decode_into(
68        &self,
69        data: &mut Reader,
70        extra: usize,
71        into: &mut Vec<u32>,
72    ) -> InternalResult<()> {
73        let range = 0..=extra;
74        match self {
75            Self::VariableSigned => into.push(variable_signed(data)?.cast_unsigned()),
76            Self::Variable => into.push(variable(data)?),
77
78            Self::Negative14Bit => into.push(negative_14_bit(data)?.cast_unsigned()),
79
80            Self::TaggedVariable => {
81                into.extend_from_slice(
82                    &tagged_variable(data, extra)?.map(i32::cast_unsigned)[range],
83                );
84            }
85            Self::Tagged32 => {
86                into.extend_from_slice(&tagged_32(data)?.map(i32::cast_unsigned)[range]);
87            }
88            Self::Tagged16 => {
89                into.extend_from_slice(
90                    &tagged_16(data)?.map(|x| i32::from(x).cast_unsigned())[range],
91                );
92            }
93
94            Self::Null => into.push(0),
95        }
96
97        Ok(())
98    }
99}
100
101#[inline]
102const fn sign_extend<const BITS: u32>(from: u32) -> i32 {
103    let unused_bits = 32 - BITS;
104    (from << unused_bits).cast_signed() >> unused_bits
105}
106
107#[inline]
108const fn zig_zag_decode(value: u32) -> i32 {
109    (value >> 1).cast_signed() ^ -(value.cast_signed() & 1)
110}
111
112#[cfg(test)]
113mod tests {
114    #[test]
115    fn sign_extend() {
116        use super::sign_extend;
117
118        assert_eq!(0, sign_extend::<2>(0b00));
119        assert_eq!(1, sign_extend::<2>(0b01));
120        assert_eq!(-2, sign_extend::<2>(0b10));
121        assert_eq!(-1, sign_extend::<2>(0b11));
122    }
123
124    #[test]
125    fn zig_zag_decode() {
126        use super::zig_zag_decode;
127
128        assert_eq!(0, zig_zag_decode(0));
129        assert_eq!(-1, zig_zag_decode(1));
130        assert_eq!(1, zig_zag_decode(2));
131        assert_eq!(-2, zig_zag_decode(3));
132
133        assert_eq!(i32::MIN, zig_zag_decode(u32::MAX));
134        assert_eq!(i32::MAX, zig_zag_decode(u32::MAX - 1));
135    }
136}