Huffman
This commit is contained in:
		| @@ -4,18 +4,247 @@ struct Node { | |||||||
|     id: Option<usize>, |     id: Option<usize>, | ||||||
|     left: Option<Box<Node>>, |     left: Option<Box<Node>>, | ||||||
|     right: Option<Box<Node>>, |     right: Option<Box<Node>>, | ||||||
|     terminal: Option<u8>, |     terminal: Option<usize>, | ||||||
|     maybe_eos: bool, |     maybe_eos: bool, | ||||||
|     transitions: RefCell<Vec<Transition>>, |     transitions: RefCell<Vec<Transition>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Default, Copy, Clone)] | #[derive(Debug, Default, Copy, Clone)] | ||||||
| struct Transition { | struct Transition { | ||||||
|     target: usize, |     target: Option<usize>, | ||||||
|     byte: Option<u8>, |     byte: Option<usize>, | ||||||
|     maybe_eos: bool, |     maybe_eos: bool, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl Node { | ||||||
|  |     fn new(byte: usize, code: &[bool]) -> Box<Node> { | ||||||
|  |         let mut node = Box::new(Node { | ||||||
|  |             id: None, | ||||||
|  |             left: None, | ||||||
|  |             right: None, | ||||||
|  |             terminal: None, | ||||||
|  |             maybe_eos: false, | ||||||
|  |             transitions: Default::default(), | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         node.insert(byte, code); | ||||||
|  |         node | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn insert(&mut self, byte: usize, code: &[bool]) { | ||||||
|  |         if code.is_empty() { | ||||||
|  |             self.terminal = Some(byte); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let (head, rest) = code.split_at(1); | ||||||
|  |  | ||||||
|  |         if !head[0] { | ||||||
|  |             match self.left { | ||||||
|  |                 Some(ref mut node) => { | ||||||
|  |                     node.insert(byte, rest); | ||||||
|  |                 } | ||||||
|  |                 None => { | ||||||
|  |                     self.left = Some(Node::new(byte, rest)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             match self.right { | ||||||
|  |                 Some(ref mut node) => { | ||||||
|  |                     node.insert(byte, rest); | ||||||
|  |                 } | ||||||
|  |                 None => { | ||||||
|  |                     self.right = Some(Node::new(byte, rest)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn set_id(&mut self, next_id: &mut usize, prefix: &mut Vec<bool>) { | ||||||
|  |         if self.terminal.is_some() { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if prefix.len() <= 7 && prefix.iter().all(|i| *i) { | ||||||
|  |             self.maybe_eos = true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let id = *next_id; | ||||||
|  |         *next_id = id + 1; | ||||||
|  |         self.id = Some(id); | ||||||
|  |  | ||||||
|  |         if let Some(ref mut node) = self.left { | ||||||
|  |             prefix.push(false); | ||||||
|  |             node.set_id(next_id, prefix); | ||||||
|  |             prefix.pop(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if let Some(ref mut node) = self.right { | ||||||
|  |             prefix.push(true); | ||||||
|  |             node.set_id(next_id, prefix); | ||||||
|  |             prefix.pop(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn compute_transitions(&self, root: &Node) { | ||||||
|  |         self.compute_transition(None, self, root, 4); | ||||||
|  |  | ||||||
|  |         if let Some(ref node) = self.left { | ||||||
|  |             node.compute_transitions(root); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if let Some(ref node) = self.right { | ||||||
|  |             node.compute_transitions(root); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn compute_transition(&self, | ||||||
|  |                           byte: Option<usize>, | ||||||
|  |                           start: &Node, | ||||||
|  |                           root: &Node, | ||||||
|  |                           steps_remaining: usize) | ||||||
|  |     { | ||||||
|  |         if steps_remaining == 0 { | ||||||
|  |             let (byte, target) = match byte { | ||||||
|  |                 Some(256) => (None, None), | ||||||
|  |                 _ => { | ||||||
|  |                     (byte, Some(self.id.unwrap_or(0))) | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             start.transitions.borrow_mut().push(Transition { | ||||||
|  |                 target: target, | ||||||
|  |                 byte: byte, | ||||||
|  |                 maybe_eos: self.maybe_eos, | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let mut next = self; | ||||||
|  |  | ||||||
|  |         if self.terminal.is_some() { | ||||||
|  |             next = root; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         assert!(next.left.is_some()); | ||||||
|  |         assert!(next.right.is_some()); | ||||||
|  |  | ||||||
|  |         for node in &[next.left.as_ref().unwrap(), next.right.as_ref().unwrap()] { | ||||||
|  |             let byte = match node.terminal { | ||||||
|  |                 Some(b) => { | ||||||
|  |                     assert!(byte.is_none()); | ||||||
|  |                     Some(b) | ||||||
|  |                 } | ||||||
|  |                 None => byte, | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             node.compute_transition(byte, start, root, steps_remaining - 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn print(&self) { | ||||||
|  |         const MAYBE_EOS: u8 = 1; | ||||||
|  |         const DECODED: u8 = 2; | ||||||
|  |         const ERROR: u8 = 4; | ||||||
|  |  | ||||||
|  |         if self.terminal.is_some() { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         println!("    // {}", self.id.unwrap()); | ||||||
|  |         println!("    ["); | ||||||
|  |  | ||||||
|  |         for transition in self.transitions.borrow().iter() { | ||||||
|  |             let mut flags = 0; | ||||||
|  |             let mut out = 0; | ||||||
|  |  | ||||||
|  |             let target = match transition.target { | ||||||
|  |                 Some(target) => target, | ||||||
|  |                 None => { | ||||||
|  |                     flags |= ERROR; | ||||||
|  |                     0 | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             if let Some(byte) = transition.byte { | ||||||
|  |                 out = byte; | ||||||
|  |                 flags |= DECODED; | ||||||
|  |  | ||||||
|  |                 // TODO: Add other flags | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if transition.maybe_eos { | ||||||
|  |                 flags |= MAYBE_EOS; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             println!("        ({}, {}, 0x{:02x}),", target, out, flags); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         println!("    ],"); | ||||||
|  |  | ||||||
|  |         self.left.as_ref().unwrap().print(); | ||||||
|  |         self.right.as_ref().unwrap().print(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Returns root of tree | ||||||
|  | fn load_table() -> Box<Node> { | ||||||
|  |     let mut lines = TABLE.lines(); | ||||||
|  |     let mut root: Option<Box<Node>> = None; | ||||||
|  |  | ||||||
|  |     // Skip the first line, which is empty | ||||||
|  |     lines.next(); | ||||||
|  |  | ||||||
|  |     for (i, line) in lines.enumerate() { | ||||||
|  |         let mut bits: Vec<bool> = vec![]; | ||||||
|  |  | ||||||
|  |         for &b in &line.as_bytes()[12..45] { | ||||||
|  |             match b { | ||||||
|  |                 b'1' => bits.push(true), | ||||||
|  |                 b'0' => bits.push(false), | ||||||
|  |                 b'|' | b' ' => {} | ||||||
|  |                 _ => panic!("unexpected byte; {:?}", b), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         match root { | ||||||
|  |             Some(ref mut node) => { | ||||||
|  |                 node.insert(i, &bits); | ||||||
|  |             } | ||||||
|  |             None => { | ||||||
|  |                 root = Some(Node::new(i, &bits)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Assign IDs to all state transition nodes | ||||||
|  |     let mut root = root.unwrap(); | ||||||
|  |     let mut id = 0; | ||||||
|  |     root.set_id(&mut id, &mut vec![]); | ||||||
|  |  | ||||||
|  |     // Compute transitions for each node | ||||||
|  |     root.compute_transitions(&root); | ||||||
|  |  | ||||||
|  |     root | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn main() { | ||||||
|  |     let table = load_table(); | ||||||
|  |  | ||||||
|  |     println!("// !!! DO NOT EDIT !!! Generated by src/bin/genhuff.rs"); | ||||||
|  |     println!(""); | ||||||
|  |  | ||||||
|  |     println!("// (next-state, byte, flags)"); | ||||||
|  |     println!("pub const DECODE_TABLE: [[(usize, u8, u8); 16]; 256] = ["); | ||||||
|  |  | ||||||
|  |     table.print(); | ||||||
|  |  | ||||||
|  |     println!("];"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| const TABLE: &'static str = r##" | const TABLE: &'static str = r##" | ||||||
|     (  0)  |11111111|11000                             1ff8  [13] |     (  0)  |11111111|11000                             1ff8  [13] | ||||||
|     (  1)  |11111111|11111111|1011000                7fffd8  [23] |     (  1)  |11111111|11111111|1011000                7fffd8  [23] | ||||||
| @@ -274,254 +503,3 @@ const TABLE: &'static str = r##" | |||||||
|     (254)  |11111111|11111111|11111110|000          7fffff0  [27] |     (254)  |11111111|11111111|11111110|000          7fffff0  [27] | ||||||
|     (255)  |11111111|11111111|11111011|10           3ffffee  [26] |     (255)  |11111111|11111111|11111011|10           3ffffee  [26] | ||||||
| EOS (256)  |11111111|11111111|11111111|111111      3fffffff  [30]"##; | EOS (256)  |11111111|11111111|11111111|111111      3fffffff  [30]"##; | ||||||
|  |  | ||||||
| const VALID_NAME_CHAR: &'static [u8] = &[ |  | ||||||
|         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //    0-31 |  | ||||||
|         0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, //   32-63 |  | ||||||
|         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, //   64-95 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0, //  96-127 |  | ||||||
|         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 128-159 |  | ||||||
|         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 160-191 |  | ||||||
|         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 192-223 |  | ||||||
|         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 224-255 |  | ||||||
| ]; |  | ||||||
|  |  | ||||||
| const VALID_VALUE_CHAR: &'static [u8] = &[ |  | ||||||
|         0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //    0-31 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //   32-63 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //   64-95 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, //  96-127 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 128-159 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 160-191 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 192-223 |  | ||||||
|         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 224-255 |  | ||||||
| ]; |  | ||||||
|  |  | ||||||
| impl Node { |  | ||||||
|     fn new(byte: u8, code: &[bool]) -> Box<Node> { |  | ||||||
|         let mut node = Box::new(Node { |  | ||||||
|             id: None, |  | ||||||
|             left: None, |  | ||||||
|             right: None, |  | ||||||
|             terminal: None, |  | ||||||
|             maybe_eos: false, |  | ||||||
|             transitions: Default::default(), |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         node.insert(byte, code); |  | ||||||
|         node |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn insert(&mut self, byte: u8, code: &[bool]) { |  | ||||||
|         if code.is_empty() { |  | ||||||
|             self.terminal = Some(byte); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         let (head, rest) = code.split_at(1); |  | ||||||
|  |  | ||||||
|         if !head[0] { |  | ||||||
|             match self.left { |  | ||||||
|                 Some(ref mut node) => { |  | ||||||
|                     node.insert(byte, rest); |  | ||||||
|                 } |  | ||||||
|                 None => { |  | ||||||
|                     self.left = Some(Node::new(byte, rest)); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             match self.right { |  | ||||||
|                 Some(ref mut node) => { |  | ||||||
|                     node.insert(byte, rest); |  | ||||||
|                 } |  | ||||||
|                 None => { |  | ||||||
|                     self.right = Some(Node::new(byte, rest)); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn set_id(&mut self, next_id: &mut usize, prefix: &mut Vec<bool>) { |  | ||||||
|         if self.terminal.is_some() { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if prefix.len() <= 7 && prefix.iter().all(|i| *i) { |  | ||||||
|             self.maybe_eos = true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         let id = *next_id; |  | ||||||
|         *next_id = id + 1; |  | ||||||
|         self.id = Some(id); |  | ||||||
|  |  | ||||||
|         if let Some(ref mut node) = self.left { |  | ||||||
|             prefix.push(false); |  | ||||||
|             node.set_id(next_id, prefix); |  | ||||||
|             prefix.pop(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if let Some(ref mut node) = self.right { |  | ||||||
|             prefix.push(true); |  | ||||||
|             node.set_id(next_id, prefix); |  | ||||||
|             prefix.pop(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn compute_transitions(&self, root: &Node) { |  | ||||||
|         self.compute_transition(None, self, root, 4); |  | ||||||
|  |  | ||||||
|         if let Some(ref node) = self.left { |  | ||||||
|             node.compute_transitions(root); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if let Some(ref node) = self.right { |  | ||||||
|             node.compute_transitions(root); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn compute_transition(&self, |  | ||||||
|                           byte: Option<u8>, |  | ||||||
|                           start: &Node, |  | ||||||
|                           root: &Node, |  | ||||||
|                           steps_remaining: usize) |  | ||||||
|     { |  | ||||||
|         let mut next = self; |  | ||||||
|  |  | ||||||
|         if self.terminal.is_some() { |  | ||||||
|             next = root; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if steps_remaining == 0 { |  | ||||||
|             start.transitions.borrow_mut().push(Transition { |  | ||||||
|                 target: next.id.unwrap(), |  | ||||||
|                 byte: byte, |  | ||||||
|                 maybe_eos: next.maybe_eos, |  | ||||||
|             }); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         assert!(next.left.is_some()); |  | ||||||
|         assert!(next.right.is_some()); |  | ||||||
|  |  | ||||||
|         for node in &[next.left.as_ref().unwrap(), next.right.as_ref().unwrap()] { |  | ||||||
|             let byte = match node.terminal { |  | ||||||
|                 Some(b) => { |  | ||||||
|                     assert!(byte.is_none()); |  | ||||||
|                     Some(b) |  | ||||||
|                 } |  | ||||||
|                 None => byte, |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             node.compute_transition(byte, start, root, steps_remaining - 1); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn print(&self) { |  | ||||||
|         const NGHTTP2_HUFF_ACCEPTED: usize = 1; |  | ||||||
|         const NGHTTP2_HUFF_SYM: usize = 1 << 1; |  | ||||||
|         const NGHTTP2_HUFF_FAIL: usize = 1 << 2; |  | ||||||
|         const NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME: usize = 1 << 3; |  | ||||||
|         const NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE: usize = 1 << 4; |  | ||||||
|         const NGHTTP2_HUFF_UPPER_CASE_CHAR: usize = 1 << 5; |  | ||||||
|  |  | ||||||
|         if self.terminal.is_some() { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         println!("    // {}", self.id.unwrap()); |  | ||||||
|         println!("    ["); |  | ||||||
|  |  | ||||||
|         for transition in self.transitions.borrow().iter() { |  | ||||||
|             let mut flags = 0; |  | ||||||
|             let mut out = 0; |  | ||||||
|             let mut target = transition.target; |  | ||||||
|  |  | ||||||
|             if let Some(byte) = transition.byte { |  | ||||||
|                 out = byte; |  | ||||||
|                 flags |= NGHTTP2_HUFF_SYM; |  | ||||||
|  |  | ||||||
|                 if VALID_NAME_CHAR[byte as usize] == 0 { |  | ||||||
|                     flags |= NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if VALID_VALUE_CHAR[byte as usize] == 0 { |  | ||||||
|                     flags |= NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 // TODO: Add other flags |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if transition.maybe_eos { |  | ||||||
|                 flags |= NGHTTP2_HUFF_ACCEPTED; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             println!("        HuffmanState {{"); |  | ||||||
|             println!("            next: {},", target); |  | ||||||
|             println!("            byte: {},", out); |  | ||||||
|             println!("            flags: {},", flags); |  | ||||||
|             println!("        }},"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         println!("    ],"); |  | ||||||
|  |  | ||||||
|         self.left.as_ref().unwrap().print(); |  | ||||||
|         self.right.as_ref().unwrap().print(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Returns root of tree |  | ||||||
| fn load_table() -> Box<Node> { |  | ||||||
|     let mut lines = TABLE.lines(); |  | ||||||
|     let mut root: Option<Box<Node>> = None; |  | ||||||
|  |  | ||||||
|     // Skip the first line, which is empty |  | ||||||
|     lines.next(); |  | ||||||
|  |  | ||||||
|     for (i, line) in lines.enumerate() { |  | ||||||
|         let mut bits: Vec<bool> = vec![]; |  | ||||||
|  |  | ||||||
|         for &b in &line.as_bytes()[12..45] { |  | ||||||
|             match b { |  | ||||||
|                 b'1' => bits.push(true), |  | ||||||
|                 b'0' => bits.push(false), |  | ||||||
|                 b'|' | b' ' => {} |  | ||||||
|                 _ => panic!("unexpected byte; {:?}", b), |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         match root { |  | ||||||
|             Some(ref mut node) => { |  | ||||||
|                 node.insert(i as u8, &bits); |  | ||||||
|             } |  | ||||||
|             None => { |  | ||||||
|                 root = Some(Node::new(i as u8, &bits)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Assign IDs to all state transition nodes |  | ||||||
|     let mut root = root.unwrap(); |  | ||||||
|     let mut id = 0; |  | ||||||
|     root.set_id(&mut id, &mut vec![]); |  | ||||||
|  |  | ||||||
|     // Compute transitions for each node |  | ||||||
|     root.compute_transitions(&root); |  | ||||||
|  |  | ||||||
|     root |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub fn main() { |  | ||||||
|     let table = load_table(); |  | ||||||
|  |  | ||||||
|     println!("// !!! DO NOT EDIT !!! Generated by src/bin/genhuff.rs"); |  | ||||||
|     println!(""); |  | ||||||
|  |  | ||||||
|     println!(r##"use super::huffman::HuffmanState;"##); |  | ||||||
|     println!(""); |  | ||||||
|  |  | ||||||
|     println!("const HUFFMAN_DECODE_TABLE: [[HuffmanState; 16]; 256] = ["); |  | ||||||
|  |  | ||||||
|     table.print(); |  | ||||||
|  |  | ||||||
|     println!("];"); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,5 +0,0 @@ | |||||||
| pub struct HuffmanState { |  | ||||||
|     pub next: usize, |  | ||||||
|     pub byte: u8, |  | ||||||
|     pub flags: u8, |  | ||||||
| } |  | ||||||
							
								
								
									
										119
									
								
								src/hpack/huffman/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/hpack/huffman/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  | mod table; | ||||||
|  |  | ||||||
|  | use self::table::DECODE_TABLE; | ||||||
|  | use hpack::DecoderError; | ||||||
|  |  | ||||||
|  | use bytes::{BytesMut, BufMut}; | ||||||
|  |  | ||||||
|  | // Constructed in the generated `table.rs` file | ||||||
|  | struct Decoder { | ||||||
|  |     state: usize, | ||||||
|  |     maybe_eos: bool, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // These flags must match the ones in genhuff.rs | ||||||
|  |  | ||||||
|  | const MAYBE_EOS: u8 = 1; | ||||||
|  | const DECODED: u8 = 2; | ||||||
|  | const ERROR: u8 = 4; | ||||||
|  |  | ||||||
|  | pub fn decode(src: &[u8]) -> Result<BytesMut, DecoderError> { | ||||||
|  |     let mut decoder = Decoder::new(); | ||||||
|  |  | ||||||
|  |     // Max compression ration is >= 0.5 | ||||||
|  |     let mut dst = BytesMut::with_capacity(src.len() << 1); | ||||||
|  |  | ||||||
|  |     for b in src { | ||||||
|  |         if let Some(b) = try!(decoder.decode4(b >> 4)) { | ||||||
|  |             dst.put_u8(b); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if let Some(b) = try!(decoder.decode4(b & 0xf)) { | ||||||
|  |             dst.put_u8(b); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if !decoder.maybe_eos { | ||||||
|  |         // TODO: handle error | ||||||
|  |         unimplemented!(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Ok(dst) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Decoder { | ||||||
|  |     fn new() -> Decoder { | ||||||
|  |         Decoder { | ||||||
|  |             state: 0, | ||||||
|  |             maybe_eos: false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Decodes 4 bits | ||||||
|  |     fn decode4(&mut self, input: u8) -> Result<Option<u8>, DecoderError> { | ||||||
|  |         // (next-state, byte, flags) | ||||||
|  |         let (next, byte, flags) = DECODE_TABLE[self.state][input as usize]; | ||||||
|  |  | ||||||
|  |         if flags & ERROR == ERROR { | ||||||
|  |             // Data followed the EOS marker | ||||||
|  |             unimplemented!(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let mut ret = None; | ||||||
|  |  | ||||||
|  |         if flags & DECODED == DECODED { | ||||||
|  |             ret = Some(byte); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self.state = next; | ||||||
|  |         self.maybe_eos = flags & MAYBE_EOS == MAYBE_EOS; | ||||||
|  |  | ||||||
|  |         Ok(ret) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cfg(test)] | ||||||
|  | mod test { | ||||||
|  |     use super::*; | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn decode_single_byte() { | ||||||
|  |         let buf = [0b00111111]; | ||||||
|  |  | ||||||
|  |         let actual = decode(&buf).unwrap(); | ||||||
|  |         assert_eq!(actual, "o"); | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |         let mut decoder = HuffmanDecoder::new(); | ||||||
|  |         // (The + (2^n - 1) at the final byte is to add the correct expected | ||||||
|  |         // padding: 1s) | ||||||
|  |         { | ||||||
|  |             // We need to shift it by 3, since we need the top-order bytes to | ||||||
|  |             // start the code point. | ||||||
|  |             let hex_buffer = [(0x7 << 3) + 7]; | ||||||
|  |             let expected_result = vec![b'o']; | ||||||
|  |  | ||||||
|  |             let result = decoder.decode(&hex_buffer).ok().unwrap(); | ||||||
|  |  | ||||||
|  |             assert_eq!(result, expected_result); | ||||||
|  |         } | ||||||
|  |         { | ||||||
|  |             let hex_buffer = [0x0 + 7]; | ||||||
|  |             let expected_result = vec![b'0']; | ||||||
|  |  | ||||||
|  |             let result = decoder.decode(&hex_buffer).ok().unwrap(); | ||||||
|  |  | ||||||
|  |             assert_eq!(result, expected_result); | ||||||
|  |         } | ||||||
|  |         { | ||||||
|  |             // The length of the codepoint is 6, so we shift by two | ||||||
|  |             let hex_buffer = [(0x21 << 2) + 3]; | ||||||
|  |             let expected_result = vec![b'A']; | ||||||
|  |  | ||||||
|  |             let result = decoder.decode(&hex_buffer).ok().unwrap(); | ||||||
|  |  | ||||||
|  |             assert_eq!(result, expected_result); | ||||||
|  |         } | ||||||
|  |         */ | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										4869
									
								
								src/hpack/huffman/table.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4869
									
								
								src/hpack/huffman/table.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -2,10 +2,9 @@ mod encoder; | |||||||
| mod decoder; | mod decoder; | ||||||
| mod entry; | mod entry; | ||||||
| mod huffman; | mod huffman; | ||||||
| mod huffman_table; |  | ||||||
| // mod table; | // mod table; | ||||||
|  |  | ||||||
| pub use self::encoder::Encoder; | pub use self::encoder::Encoder; | ||||||
| pub use self::entry::Entry; | pub use self::entry::Entry; | ||||||
| pub use self::decoder::Decoder; | pub use self::decoder::{Decoder, DecoderError}; | ||||||
| // pub use self::table::Entry; | // pub use self::table::Entry; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user