Skip to main content

proto_packet/io/wire/
bits.rs

1use crate::io::WireType;
2
3impl WireType {
4    //! Bits
5
6    /// Gets the wire type from the low 3-bits of `b`.
7    pub fn from_low_3_bits(b: u8) -> Self {
8        // `WireType` is `#[repr(u8)]` with discriminants `0..=7`, so every value of `b & 0x7`
9        // is a valid discriminant.
10        unsafe { std::mem::transmute::<u8, WireType>(b & 0x7) }
11    }
12
13    /// Gets the wire type from the high 3-bits of `b`.
14    pub fn from_high_3_bits(b: u8) -> Self {
15        Self::from_low_3_bits(b >> 5)
16    }
17
18    /// Converts the wire type to the low 3-bits of a `u8`.
19    pub fn to_low_3_bits(self) -> u8 {
20        self as u8
21    }
22
23    /// Converts the wire type to the high 3-bits of a `u8`.
24    pub fn to_high_3_bits(self) -> u8 {
25        (self as u8) << 5
26    }
27}
28
29#[cfg(test)]
30mod tests {
31    use crate::io::WireType;
32    use crate::io::WireType::*;
33
34    #[test]
35    fn from_low_3_bits() {
36        let cases: &[(u8, WireType)] = &[
37            (0b0000_0000, Fixed1Byte),
38            (0b0000_0001, Fixed2Byte),
39            (0b0000_0010, Fixed4Byte),
40            (0b0000_0011, Fixed8Byte),
41            (0b0000_0100, Fixed16Byte),
42            (0b0000_0101, VarInt),
43            (0b0000_0110, LengthPrefixed),
44            (0b0000_0111, List),
45            // High bits are masked off — these should still produce the same results.
46            (0b1111_1000, Fixed1Byte),
47            (0b1111_1101, VarInt),
48        ];
49        for (input, expected) in cases {
50            assert_eq!(
51                WireType::from_low_3_bits(*input),
52                *expected,
53                "input={input:#010b}"
54            );
55        }
56    }
57
58    #[test]
59    fn from_high_3_bits() {
60        let cases: &[(u8, WireType)] = &[
61            (0b0000_0000, Fixed1Byte),
62            (0b0010_0000, Fixed2Byte),
63            (0b0100_0000, Fixed4Byte),
64            (0b0110_0000, Fixed8Byte),
65            (0b1000_0000, Fixed16Byte),
66            (0b1010_0000, VarInt),
67            (0b1100_0000, LengthPrefixed),
68            (0b1110_0000, List),
69            // Low bits are ignored — these should still produce the same results.
70            (0b0001_1111, Fixed1Byte),
71            (0b1011_1111, VarInt),
72        ];
73        for (input, expected) in cases {
74            assert_eq!(
75                WireType::from_high_3_bits(*input),
76                *expected,
77                "input={input:#010b}"
78            );
79        }
80    }
81
82    #[test]
83    fn to_low_3_bits() {
84        let cases: &[(WireType, u8)] = &[
85            (Fixed1Byte, 0b0000_0000),
86            (Fixed2Byte, 0b0000_0001),
87            (Fixed4Byte, 0b0000_0010),
88            (Fixed8Byte, 0b0000_0011),
89            (Fixed16Byte, 0b0000_0100),
90            (VarInt, 0b0000_0101),
91            (LengthPrefixed, 0b0000_0110),
92            (List, 0b0000_0111),
93        ];
94        for (wire, expected) in cases {
95            assert_eq!(wire.to_low_3_bits(), *expected, "wire={wire:?}");
96        }
97    }
98
99    #[test]
100    fn to_high_3_bits() {
101        let cases: &[(WireType, u8)] = &[
102            (Fixed1Byte, 0b0000_0000),
103            (Fixed2Byte, 0b0010_0000),
104            (Fixed4Byte, 0b0100_0000),
105            (Fixed8Byte, 0b0110_0000),
106            (Fixed16Byte, 0b1000_0000),
107            (VarInt, 0b1010_0000),
108            (LengthPrefixed, 0b1100_0000),
109            (List, 0b1110_0000),
110        ];
111        for (wire, expected) in cases {
112            assert_eq!(wire.to_high_3_bits(), *expected, "wire={wire:?}");
113        }
114    }
115}