httlib_huffman/parser/
mod.rs

1//! Provides features for parsing [Huffman code] table provided by the [HPACK]
2//! documentation.
3//! 
4//! [HPACK] provides a pre-created [Huffman code] table for encoding [ASCII]
5//! characters to the Huffman sequence. This Huffman code was generated from
6//! statistics obtained on a large sample of HTTP headers.
7//! 
8//! The parser module is responsible for parsing the [Huffman code] table into
9//! the static Rust source code. This module was used to create the ENCODE_TABLE
10//! constant which can be found in the `encode::table` module.
11//! 
12//! You will probably never use this module while developing applications.
13//! 
14//! [ASCII]: https://en.wikipedia.org/wiki/ASCII
15//! [HPACK]: https://tools.ietf.org/html/rfc7541
16//! [Huffman code]: https://tools.ietf.org/html/rfc7541#appendix-B
17
18/// Parses the HPACK's static Huffman table. The function expects data to be in
19/// format as provided by the spec (7.2).
20/// 
21/// **Example:**
22/// 
23/// ```rust
24/// use std::fs;
25/// use std::path::Path;
26/// use httlib_huffman::parser::parse;
27/// 
28/// let path = Path::new("assets/hpack-huffman.txt");
29/// let data = fs::read_to_string(path).expect("Can't read file.");
30/// let codings = parse(&data);
31/// ```
32pub fn parse(data: &str) -> Vec<(u16, u32)> {
33    let lines = data.lines();
34    let mut codings = vec![];
35
36    for line in lines {
37        let coding = parse_line(line);
38        codings.push(coding);
39    }
40
41    codings
42}
43
44/// Parses a single line of the static Huffman table. The output returned
45/// contains a tuple of the number of bits for the code representing the symbol
46/// and Huffman LSB value.
47fn parse_line(line: &str) -> (u16, u32) {
48
49    let mut msb = vec![];
50    for &b in &line.as_bytes()[12..45] {
51        match b {
52            b'1' => msb.push(true),
53            b'0' => msb.push(false),
54            b'|' | b' ' => {}
55            _ => panic!("unexpected byte; {:?}", b),
56        }
57    }
58
59    let lsb = u32::from_str_radix(&line[50..59].trim().to_string(), 16).expect("Invalid hex");
60    let len = msb.len() as u16;
61
62    (len, lsb)
63}
64
65#[cfg(test)]
66mod tests {
67    use std::fs;
68    use std::path::Path;
69    use super::*;
70
71    /// Should read the text file `assets/hpack-huffman.txt` and parse the 
72    /// content into 2-dimensional table that can be used in Rust code. 
73    #[test]
74    fn parses_huffman_table() { 
75        let path = Path::new("assets/hpack-huffman.txt");
76        let data = fs::read_to_string(path).expect("Can't read file.");
77        let table = parse(&data);
78
79        assert_eq!(table.len(), 257);
80
81        let item = table[10];
82        assert_eq!(item.0, 30);
83        assert_eq!(item.1, 0x3ffffffc);
84
85        let item = table[32];
86        assert_eq!(item.0, 6);
87        assert_eq!(item.1, 0x14);
88
89        let item = table.last().unwrap();
90        assert_eq!(item.0, 30);
91        assert_eq!(item.1, 0x3fffffff);
92    }
93}