dash7/
types.rs

1use deku::{
2    bitvec::{BitSlice, BitVec, Msb0},
3    ctx::{BitSize, Endian},
4    prelude::*,
5};
6
7#[derive(Debug, Clone, PartialEq)]
8pub enum VarIntError {
9    ValueTooLarge(u32),
10    ExponentTooLarge(u8),
11    MantissaTooLarge(u8),
12    Unknown,
13}
14
15impl Into<DekuError> for VarIntError {
16    fn into(self) -> DekuError {
17        match self {
18            VarIntError::ValueTooLarge(value) => DekuError::InvalidParam(format!(
19                "VarInt: Value too large: {:?}. Max: {:?}",
20                value,
21                VarInt::MAX
22            )),
23            VarIntError::ExponentTooLarge(exponent) => DekuError::InvalidParam(format!(
24                "VarInt: Exponent too large {:?}. Max: {:?}",
25                exponent,
26                2 ^ 3
27            )),
28            VarIntError::MantissaTooLarge(mantissa) => DekuError::InvalidParam(format!(
29                "VarInt: Mantissa too large {:?}. Max: {:?}",
30                mantissa,
31                2 ^ 5
32            )),
33            VarIntError::Unknown => DekuError::Unexpected("VarInt: Unknown error".to_string()),
34        }
35    }
36}
37
38/// Variable int format
39/// SPEC: 6.2.2 Compressed Format
40#[derive(DekuRead, DekuWrite, Default, Debug, Clone, Copy, PartialEq)]
41pub struct VarInt {
42    #[deku(
43        reader = "VarInt::read(deku::rest)",
44        writer = "VarInt::write(deku::output, &self.value, &self.ceil)"
45    )]
46    value: u32,
47
48    #[deku(skip, default = "false")]
49    ceil: bool,
50}
51
52impl VarInt {
53    pub const MAX: u32 = 507904;
54
55    pub fn new(value: u32, ceil: bool) -> Result<Self, VarIntError> {
56        if !Self::is_valid(value) {
57            Err(VarIntError::ValueTooLarge(value))
58        } else {
59            Ok(Self { value, ceil })
60        }
61    }
62
63    pub fn new_unchecked(value: u32, ceil: bool) -> Self {
64        Self { value, ceil }
65    }
66
67    pub fn decompress(exponent: u8, mantissa: u8) -> Result<u32, VarIntError> {
68        if exponent & 0b11111000 > 0 {
69            return Err(VarIntError::ExponentTooLarge(exponent));
70        }
71
72        if mantissa & 0b11100000 > 0 {
73            return Err(VarIntError::ExponentTooLarge(mantissa));
74        }
75
76        Ok(4u32.pow(exponent as u32) * mantissa as u32)
77    }
78
79    pub fn compress(
80        value: u32,
81        ceil: bool,
82    ) -> Result<(/*exponent: */ u8, /*mantissa: */ u8), VarIntError> {
83        if !Self::is_valid(value) {
84            return Err(VarIntError::ValueTooLarge(value));
85        }
86
87        for i in 0..8 {
88            let exp = 4u32.pow(i);
89
90            if value <= (exp * 31) {
91                let mut mantissa = value / exp;
92                let remainder = value % exp;
93
94                if ceil && remainder > 0 {
95                    mantissa += 1;
96                }
97                return Ok((i as u8, mantissa as u8));
98            }
99        }
100
101        // TODO when does this happen?
102        Err(VarIntError::Unknown)
103    }
104
105    /// Returns whether the value is encodable into a VarInt or not.
106    /// Makes no guarantees about precision
107    pub fn is_valid(n: u32) -> bool {
108        n <= Self::MAX
109    }
110
111    fn read(rest: &BitSlice<u8, Msb0>) -> Result<(&BitSlice<u8, Msb0>, u32), DekuError> {
112        let (rest, exponent) = <u8 as DekuRead<'_, _>>::read(rest, (Endian::Big, BitSize(3)))?;
113        let (rest, mantissa) = <u8 as DekuRead<'_, _>>::read(rest, (Endian::Big, BitSize(5)))?;
114
115        Self::decompress(exponent, mantissa)
116            .map_err(Into::into)
117            .map(|value| (rest, value))
118    }
119
120    fn write(output: &mut BitVec<u8, Msb0>, value: &u32, ceil: &bool) -> Result<(), DekuError> {
121        match Self::compress(*value, *ceil) {
122            Ok((exponent, mantissa)) => {
123                DekuWrite::write(&exponent, output, (Endian::Big, BitSize(3)))?;
124                DekuWrite::write(&mantissa, output, (Endian::Big, BitSize(5)))?;
125                Ok(())
126            }
127            Err(err) => Err(err.into()),
128        }
129    }
130}
131
132impl Into<u32> for VarInt {
133    fn into(self) -> u32 {
134        self.value as u32
135    }
136}
137
138impl From<u32> for VarInt {
139    fn from(value: u32) -> Self {
140        Self { value, ceil: false }
141    }
142}
143
144#[cfg(test)]
145mod test {
146    use super::*;
147    use crate::test_tools::test_item;
148
149    #[test]
150    fn test_is_valid() {
151        assert!(VarInt::is_valid(507904));
152        assert!(!VarInt::is_valid(0x40_00_00_00));
153    }
154
155    #[test]
156    fn test_decompress() {
157        assert_eq!(0, VarInt::decompress(0, 0).unwrap());
158        assert_eq!(4, VarInt::decompress(1, 1).unwrap());
159        assert_eq!(32, VarInt::decompress(2, 2).unwrap());
160        assert_eq!(192, VarInt::decompress(3, 3).unwrap());
161        assert_eq!(507904, VarInt::decompress(7, 31).unwrap());
162    }
163
164    #[test]
165    fn test() {
166        test_item(VarInt::default(), &[0x00]);
167        test_item(VarInt::new_unchecked(1, false), &[0x01u8]);
168        test_item(VarInt::new_unchecked(32, false), &[0b00101000u8]);
169        test_item(VarInt::new_unchecked(507904, false), &[0xFFu8]);
170    }
171}