blackbox_log/parser/decode/
tagged_16.rs

1use super::sign_extend;
2use crate::parser::{InternalError, InternalResult};
3use crate::Reader;
4
5const COUNT: usize = 4;
6
7pub(crate) fn tagged_16(data: &mut Reader) -> InternalResult<[i16; COUNT]> {
8    let tags = data.read_u8().ok_or(InternalError::Eof)?;
9
10    if tags == 0 {
11        return Ok([0; COUNT]);
12    }
13
14    let mut result = [0; COUNT];
15    let mut aligned = true;
16    let mut buffer = 0;
17
18    for (i, result) in result.iter_mut().enumerate() {
19        *result = match (tags >> (i * 2)) & 3 {
20            0 => 0,
21            1 => {
22                let nibble = if aligned {
23                    buffer = data.read_u8().ok_or(InternalError::Eof)?;
24                    buffer >> 4
25                } else {
26                    buffer & 0xF
27                };
28
29                aligned = !aligned;
30                i4_to_i16(nibble)
31            }
32            2 => {
33                let byte = if aligned {
34                    data.read_i8().ok_or(InternalError::Eof)?
35                } else {
36                    let upper = buffer << 4;
37                    buffer = data.read_u8().ok_or(InternalError::Eof)?;
38                    (upper | (buffer >> 4)).cast_signed()
39                };
40
41                byte.into()
42            }
43            3.. => {
44                if aligned {
45                    data.read_i16().ok_or(InternalError::Eof)?.swap_bytes()
46                } else {
47                    let upper = u16::from(buffer) << 12;
48                    let [middle, lower] = data.read_u16().ok_or(InternalError::Eof)?.to_le_bytes();
49
50                    buffer = lower;
51                    (upper | (u16::from(middle) << 4) | u16::from(lower >> 4)).cast_signed()
52                }
53            }
54        }
55    }
56
57    Ok(result)
58}
59
60#[inline]
61fn i4_to_i16(nibble: u8) -> i16 {
62    sign_extend::<4>(nibble.into()) as i16
63}
64
65#[cfg(test)]
66mod tests {
67    use alloc::vec::Vec;
68    use core::iter;
69
70    use test_case::case;
71
72    use super::*;
73
74    fn bytes(first: u8, zeros: usize) -> Vec<u8> {
75        iter::once(first).chain(iter::repeat_n(0, zeros)).collect()
76    }
77
78    #[test]
79    fn all_zeros() {
80        let bytes = bytes(0x00, 0);
81        let bytes = bytes.as_slice();
82
83        assert_eq!([0; 4], tagged_16(&mut Reader::new(bytes)).unwrap());
84    }
85
86    #[test]
87    fn all_nibbles() {
88        let bytes = bytes(0x55, 2);
89        let bytes = bytes.as_slice();
90
91        assert_eq!([0; 4], tagged_16(&mut Reader::new(bytes)).unwrap());
92    }
93
94    #[test]
95    fn all_bytes() {
96        let bytes = bytes(0xAA, 4);
97        let bytes = bytes.as_slice();
98
99        assert_eq!([0; 4], tagged_16(&mut Reader::new(bytes)).unwrap());
100    }
101
102    #[test]
103    fn all_16_bits() {
104        let bytes: &[u8] = &[0xFF, 0, 1, 0, 2, 0, 3, 0, 4];
105        let mut bits = Reader::new(bytes);
106
107        let expected = [1, 2, 3, 4];
108        assert_eq!(expected, tagged_16(&mut bits).unwrap());
109    }
110
111    #[test]
112    fn tag_order_v2() {
113        let bytes: &[u8] = &[0b1110_0100, 0x10, 0x20, 0x00, 0x30];
114        let mut bits = Reader::new(bytes);
115
116        assert_eq!([0, 1, 2, 3], tagged_16(&mut bits).unwrap());
117    }
118
119    #[case( &[0x30, 181, 61] => [0, 0, -19139, 0] ; "16 bit high byte first")]
120    fn regressions(bytes: &[u8]) -> [i16; 4] {
121        let mut bits = Reader::new(bytes);
122        tagged_16(&mut bits).unwrap()
123    }
124}