Skip to main content

h2/hpack/huffman/
encode.rs

1use crate::hpack::huffman::table::{ENCODE_CODES, ENCODE_CODE_LENGTHS};
2
3use bytes::{BufMut, BytesMut};
4
5pub fn encode(src: &[u8], dst: &mut BytesMut) {
6    let mut bits = 0u64;
7    let mut bits_len = 0;
8
9    for &b in src {
10        let nbits = ENCODE_CODE_LENGTHS[b as usize] as usize;
11        let code = ENCODE_CODES[b as usize] as u64;
12
13        bits = (bits << nbits) | code;
14        bits_len += nbits;
15
16        if bits_len >= 32 {
17            let remaining = bits_len - 32;
18            dst.put_u32((bits >> remaining) as u32);
19
20            bits_len = remaining;
21            if remaining == 0 {
22                bits = 0;
23            } else {
24                bits &= (1 << remaining) - 1;
25            }
26        }
27    }
28
29    if bits_len != 0 {
30        // Pad the final byte with the EOS prefix (all ones).
31        let padding = 8 - (bits_len % 8);
32        let padding = if padding == 8 { 0 } else { padding };
33        bits = (bits << padding) | ((1 << padding) - 1);
34        bits_len += padding;
35
36        while bits_len != 0 {
37            bits_len -= 8;
38            dst.put_u8((bits >> bits_len) as u8);
39        }
40    }
41}
42
43#[cfg(test)]
44mod test {
45    use super::*;
46
47    #[test]
48    fn encode_single_byte() {
49        let mut dst = BytesMut::with_capacity(1);
50
51        encode(b"o", &mut dst);
52        assert_eq!(&dst[..], &[0b00111111]);
53
54        dst.clear();
55        encode(b"0", &mut dst);
56        assert_eq!(&dst[..], &[7]);
57
58        dst.clear();
59        encode(b"A", &mut dst);
60        assert_eq!(&dst[..], &[(0x21 << 2) + 3]);
61    }
62
63    #[test]
64    fn encode_rfc_example() {
65        let mut dst = BytesMut::new();
66
67        encode(b"www.example.com", &mut dst);
68
69        assert_eq!(
70            &dst[..],
71            &[0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff]
72        );
73    }
74}
75
76/*
77// uncomment to run benchmarks
78#[cfg(test)]
79mod bench {
80    extern crate test;
81
82    use self::test::{black_box, Bencher};
83    use super::*;
84
85    fn encode_input(b: &mut Bencher, input: &[u8]) {
86        let mut encoded = BytesMut::new();
87        encode(input, &mut encoded);
88
89        b.bytes = input.len() as u64;
90        b.iter(|| {
91            encoded.clear();
92            encode(black_box(input), &mut encoded);
93            black_box(encoded.as_ref());
94        });
95    }
96
97    #[bench]
98    fn encode_short_ascii(b: &mut Bencher) {
99        encode_input(b, b"www.example.com");
100    }
101
102    #[bench]
103    fn encode_header_value(b: &mut Bencher) {
104        encode_input(
105            b,
106            b"text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8",
107        );
108    }
109
110    #[bench]
111    fn encode_long_ascii(b: &mut Bencher) {
112        encode_input(
113            b,
114            b"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0",
115        );
116    }
117
118    #[bench]
119    fn encode_all_octets(b: &mut Bencher) {
120        let input: Vec<_> = (0..=u8::MAX).collect();
121        encode_input(b, &input);
122    }
123}
124*/