lightws/frame/
length.rs

1//! Payload length.
2
3/// Payload length.
4///
5/// Could be 7 bits, 7+16 bits, or 7+64 bits.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum PayloadLen {
8    /// 0 - 125
9    Standard(u8),
10    /// 126 - 65535
11    Extended1(u16),
12    /// over 65536
13    Extended2(u64),
14}
15
16impl PayloadLen {
17    /// Parse from number.
18    #[inline]
19    pub const fn from_num(n: u64) -> Self {
20        if n < 126 {
21            PayloadLen::Standard(n as u8)
22        } else if n < 65536 {
23            PayloadLen::Extended1(n as u16)
24        } else {
25            PayloadLen::Extended2(n)
26        }
27    }
28
29    /// Convert to number.
30    #[inline]
31    pub const fn to_num(self) -> u64 {
32        use PayloadLen::*;
33        match self {
34            Standard(v) => v as u64,
35            Extended1(v) => v as u64,
36            Extended2(v) => v,
37        }
38    }
39
40    /// Read the flag which indicates the kind of length.
41    ///
42    /// If extended length is used, the caller should read the next 2 or 8 bytes
43    /// to get the real length.
44    #[inline]
45    pub const fn from_flag(b: u8) -> Self {
46        match b & 0x7f {
47            126 => PayloadLen::Extended1(0),
48            127 => PayloadLen::Extended2(0),
49            b => PayloadLen::Standard(b),
50        }
51    }
52
53    /// Generate the flag byte.
54    /// If `length <= 125`, it represents the real length.
55    #[inline]
56    pub const fn to_flag(&self) -> u8 {
57        use PayloadLen::*;
58        match self {
59            Standard(b) => *b,
60            Extended1(_) => 126,
61            Extended2(_) => 127,
62        }
63    }
64
65    /// Read as 16-bit length.
66    #[inline]
67    pub const fn from_byte2(buf: [u8; 2]) -> Self { PayloadLen::Extended1(u16::from_be_bytes(buf)) }
68
69    /// Read as 64-bit length.
70    #[inline]
71    pub const fn from_byte8(buf: [u8; 8]) -> Self { PayloadLen::Extended2(u64::from_be_bytes(buf)) }
72
73    /// Get value, as 8-bit length.
74    #[inline]
75    pub const fn to_u8(&self) -> u8 {
76        match self {
77            PayloadLen::Standard(v) => *v,
78            _ => unreachable!(),
79        }
80    }
81
82    /// Get value, as 16-bit length.
83    #[inline]
84    pub const fn to_u16(&self) -> u16 {
85        match self {
86            PayloadLen::Extended1(v) => *v,
87            _ => unreachable!(),
88        }
89    }
90
91    /// Get value, as 64-bit length.
92    #[inline]
93    pub const fn to_u64(&self) -> u64 {
94        match self {
95            PayloadLen::Extended2(v) => *v,
96            _ => unreachable!(),
97        }
98    }
99}
100
101#[cfg(test)]
102mod test {
103    use super::*;
104
105    #[test]
106    fn standard() {
107        for v in 0..=125_u8 {
108            let a = PayloadLen::from_flag(v);
109            let b = PayloadLen::from_num(v as u64);
110
111            assert_eq!(a.to_flag(), v);
112            assert_eq!(a.to_num(), b.to_num());
113        }
114    }
115
116    #[test]
117    fn extend1() {
118        for v in 126..=65535_u16 {
119            let a = PayloadLen::from_num(v as u64);
120            let b = PayloadLen::from_byte2(v.to_be_bytes());
121
122            assert_eq!(a.to_flag(), 126_u8);
123            assert_eq!(a.to_num(), b.to_num());
124        }
125    }
126
127    #[test]
128    fn extend2() {
129        for v in 65536..=100000_u64 {
130            let a = PayloadLen::from_num(v);
131            let b = PayloadLen::from_byte8(v.to_be_bytes());
132
133            assert_eq!(a.to_flag(), 127_u8);
134            assert_eq!(a.to_num(), b.to_num());
135        }
136    }
137}