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*/