blackbox_log/parser/decode/
tagged_16.rs1use 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}