/rust/registry/src/index.crates.io-1949cf8c6b5b557f/bitstream-io-1.10.0/src/huffman.rs
Line | Count | Source |
1 | | // Copyright 2017 Brian Langenberger |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
4 | | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
5 | | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
6 | | // option. This file may not be copied, modified, or distributed |
7 | | // except according to those terms. |
8 | | |
9 | | //! Traits and implementations for reading or writing Huffman codes |
10 | | //! from or to a stream. |
11 | | |
12 | | #![warn(missing_docs)] |
13 | | |
14 | | use super::BitQueue; |
15 | | use super::Endianness; |
16 | | use std::collections::BTreeMap; |
17 | | use std::fmt; |
18 | | use std::marker::PhantomData; |
19 | | |
20 | | /// A compiled Huffman tree element for use with the `read_huffman` method. |
21 | | /// Returned by `compile_read_tree`. |
22 | | /// |
23 | | /// Compiled read trees are optimized for faster lookup |
24 | | /// and are therefore endian-specific. |
25 | | /// |
26 | | /// In addition, each symbol in the source tree may occur many times |
27 | | /// in the compiled tree. If symbols require a nontrivial amount of space, |
28 | | /// consider using reference counting so that they may be cloned |
29 | | /// more efficiently. |
30 | | pub enum ReadHuffmanTree<E: Endianness, T: Clone> { |
31 | | /// The final value and new reader state |
32 | | Done(T, u8, u32, PhantomData<E>), |
33 | | /// Another byte is necessary to determine final value |
34 | | Continue(Box<[ReadHuffmanTree<E, T>]>), |
35 | | /// An invalid reader state has been used |
36 | | InvalidState, |
37 | | } |
38 | | |
39 | | /// Given a vector of symbol/code pairs, compiles a Huffman tree |
40 | | /// for reading. |
41 | | /// |
42 | | /// Code must be 0 or 1 bits and are always read from the stream |
43 | | /// from least-significant in the list to most signficant |
44 | | /// (which makes them easier to read for humans). |
45 | | /// |
46 | | /// All possible codes must be assigned some symbol, |
47 | | /// and it is acceptable for the same symbol to occur multiple times. |
48 | | /// |
49 | | /// ## Examples |
50 | | /// ``` |
51 | | /// use bitstream_io::huffman::compile_read_tree; |
52 | | /// use bitstream_io::BigEndian; |
53 | | /// assert!(compile_read_tree::<BigEndian,i32>( |
54 | | /// vec![(1, vec![0]), |
55 | | /// (2, vec![1, 0]), |
56 | | /// (3, vec![1, 1])]).is_ok()); |
57 | | /// ``` |
58 | | /// |
59 | | /// ``` |
60 | | /// use std::io::{Read, Cursor}; |
61 | | /// use bitstream_io::{BigEndian, BitReader, HuffmanRead}; |
62 | | /// use bitstream_io::huffman::compile_read_tree; |
63 | | /// let tree = compile_read_tree( |
64 | | /// vec![('a', vec![0]), |
65 | | /// ('b', vec![1, 0]), |
66 | | /// ('c', vec![1, 1, 0]), |
67 | | /// ('d', vec![1, 1, 1])]).unwrap(); |
68 | | /// let data = [0b10110111]; |
69 | | /// let mut cursor = Cursor::new(&data); |
70 | | /// let mut reader = BitReader::endian(&mut cursor, BigEndian); |
71 | | /// assert_eq!(reader.read_huffman(&tree).unwrap(), 'b'); |
72 | | /// assert_eq!(reader.read_huffman(&tree).unwrap(), 'c'); |
73 | | /// assert_eq!(reader.read_huffman(&tree).unwrap(), 'd'); |
74 | | /// ``` |
75 | 1.17M | pub fn compile_read_tree<E, T>( |
76 | 1.17M | values: Vec<(T, Vec<u8>)>, |
77 | 1.17M | ) -> Result<Box<[ReadHuffmanTree<E, T>]>, HuffmanTreeError> |
78 | 1.17M | where |
79 | 1.17M | E: Endianness, |
80 | 1.17M | T: Clone, |
81 | | { |
82 | 1.17M | let tree = FinalHuffmanTree::new(values)?; |
83 | | |
84 | 1.17M | let mut result = Vec::with_capacity(256); |
85 | 1.17M | result.extend((0..256).map(|_| ReadHuffmanTree::InvalidState)); |
86 | 1.17M | let queue = BitQueue::from_value(0, 0); |
87 | 1.17M | let i = queue.to_state(); |
88 | 1.17M | result[i] = compile_queue(queue, &tree); |
89 | 9.40M | for bits in 1..8 { |
90 | 298M | for value in 0..(1 << bits) { |
91 | 298M | let queue = BitQueue::from_value(value, bits); |
92 | 298M | let i = queue.to_state(); |
93 | 298M | result[i] = compile_queue(queue, &tree); |
94 | 298M | } |
95 | | } |
96 | 1.17M | assert_eq!(result.len(), 256); |
97 | 1.17M | Ok(result.into_boxed_slice()) |
98 | 1.17M | } bitstream_io::huffman::compile_read_tree::<bitstream_io::LittleEndian, u8> Line | Count | Source | 75 | 960k | pub fn compile_read_tree<E, T>( | 76 | 960k | values: Vec<(T, Vec<u8>)>, | 77 | 960k | ) -> Result<Box<[ReadHuffmanTree<E, T>]>, HuffmanTreeError> | 78 | 960k | where | 79 | 960k | E: Endianness, | 80 | 960k | T: Clone, | 81 | | { | 82 | 960k | let tree = FinalHuffmanTree::new(values)?; | 83 | | | 84 | 960k | let mut result = Vec::with_capacity(256); | 85 | 960k | result.extend((0..256).map(|_| ReadHuffmanTree::InvalidState)); | 86 | 960k | let queue = BitQueue::from_value(0, 0); | 87 | 960k | let i = queue.to_state(); | 88 | 960k | result[i] = compile_queue(queue, &tree); | 89 | 7.68M | for bits in 1..8 { | 90 | 243M | for value in 0..(1 << bits) { | 91 | 243M | let queue = BitQueue::from_value(value, bits); | 92 | 243M | let i = queue.to_state(); | 93 | 243M | result[i] = compile_queue(queue, &tree); | 94 | 243M | } | 95 | | } | 96 | 960k | assert_eq!(result.len(), 256); | 97 | 960k | Ok(result.into_boxed_slice()) | 98 | 960k | } |
bitstream_io::huffman::compile_read_tree::<bitstream_io::LittleEndian, u16> Line | Count | Source | 75 | 216k | pub fn compile_read_tree<E, T>( | 76 | 216k | values: Vec<(T, Vec<u8>)>, | 77 | 216k | ) -> Result<Box<[ReadHuffmanTree<E, T>]>, HuffmanTreeError> | 78 | 216k | where | 79 | 216k | E: Endianness, | 80 | 216k | T: Clone, | 81 | | { | 82 | 216k | let tree = FinalHuffmanTree::new(values)?; | 83 | | | 84 | 216k | let mut result = Vec::with_capacity(256); | 85 | 216k | result.extend((0..256).map(|_| ReadHuffmanTree::InvalidState)); | 86 | 216k | let queue = BitQueue::from_value(0, 0); | 87 | 216k | let i = queue.to_state(); | 88 | 216k | result[i] = compile_queue(queue, &tree); | 89 | 1.72M | for bits in 1..8 { | 90 | 54.8M | for value in 0..(1 << bits) { | 91 | 54.8M | let queue = BitQueue::from_value(value, bits); | 92 | 54.8M | let i = queue.to_state(); | 93 | 54.8M | result[i] = compile_queue(queue, &tree); | 94 | 54.8M | } | 95 | | } | 96 | 216k | assert_eq!(result.len(), 256); | 97 | 216k | Ok(result.into_boxed_slice()) | 98 | 216k | } |
Unexecuted instantiation: bitstream_io::huffman::compile_read_tree::<_, _> |
99 | | |
100 | 1.24G | fn compile_queue<E, T>( |
101 | 1.24G | mut queue: BitQueue<E, u8>, |
102 | 1.24G | tree: &FinalHuffmanTree<T>, |
103 | 1.24G | ) -> ReadHuffmanTree<E, T> |
104 | 1.24G | where |
105 | 1.24G | E: Endianness, |
106 | 1.24G | T: Clone, |
107 | | { |
108 | 1.24G | match tree { |
109 | 614M | FinalHuffmanTree::Leaf(ref value) => { |
110 | 614M | let len = queue.len(); |
111 | 614M | ReadHuffmanTree::Done(value.clone(), queue.value(), len, PhantomData) |
112 | | } |
113 | 630M | FinalHuffmanTree::Tree(ref bit0, ref bit1) => { |
114 | 630M | if queue.is_empty() { |
115 | | ReadHuffmanTree::Continue( |
116 | 1.23M | (0..256) |
117 | 316M | .map(|byte| compile_queue(BitQueue::from_value(byte as u8, 8), tree)) bitstream_io::huffman::compile_queue::<bitstream_io::LittleEndian, u8>::{closure#0}Line | Count | Source | 117 | 245M | .map(|byte| compile_queue(BitQueue::from_value(byte as u8, 8), tree)) |
bitstream_io::huffman::compile_queue::<bitstream_io::LittleEndian, u16>::{closure#0}Line | Count | Source | 117 | 70.2M | .map(|byte| compile_queue(BitQueue::from_value(byte as u8, 8), tree)) |
Unexecuted instantiation: bitstream_io::huffman::compile_queue::<_, _>::{closure#0} |
118 | 1.23M | .collect::<Vec<ReadHuffmanTree<E, T>>>() |
119 | 1.23M | .into_boxed_slice(), |
120 | | ) |
121 | 629M | } else if queue.pop(1) == 0 { |
122 | 314M | compile_queue(queue, bit0) |
123 | | } else { |
124 | 314M | compile_queue(queue, bit1) |
125 | | } |
126 | | } |
127 | | } |
128 | 1.24G | } bitstream_io::huffman::compile_queue::<bitstream_io::LittleEndian, u8> Line | Count | Source | 100 | 980M | fn compile_queue<E, T>( | 101 | 980M | mut queue: BitQueue<E, u8>, | 102 | 980M | tree: &FinalHuffmanTree<T>, | 103 | 980M | ) -> ReadHuffmanTree<E, T> | 104 | 980M | where | 105 | 980M | E: Endianness, | 106 | 980M | T: Clone, | 107 | | { | 108 | 980M | match tree { | 109 | 489M | FinalHuffmanTree::Leaf(ref value) => { | 110 | 489M | let len = queue.len(); | 111 | 489M | ReadHuffmanTree::Done(value.clone(), queue.value(), len, PhantomData) | 112 | | } | 113 | 490M | FinalHuffmanTree::Tree(ref bit0, ref bit1) => { | 114 | 490M | if queue.is_empty() { | 115 | | ReadHuffmanTree::Continue( | 116 | 960k | (0..256) | 117 | 960k | .map(|byte| compile_queue(BitQueue::from_value(byte as u8, 8), tree)) | 118 | 960k | .collect::<Vec<ReadHuffmanTree<E, T>>>() | 119 | 960k | .into_boxed_slice(), | 120 | | ) | 121 | 489M | } else if queue.pop(1) == 0 { | 122 | 244M | compile_queue(queue, bit0) | 123 | | } else { | 124 | 244M | compile_queue(queue, bit1) | 125 | | } | 126 | | } | 127 | | } | 128 | 980M | } |
bitstream_io::huffman::compile_queue::<bitstream_io::LittleEndian, u16> Line | Count | Source | 100 | 265M | fn compile_queue<E, T>( | 101 | 265M | mut queue: BitQueue<E, u8>, | 102 | 265M | tree: &FinalHuffmanTree<T>, | 103 | 265M | ) -> ReadHuffmanTree<E, T> | 104 | 265M | where | 105 | 265M | E: Endianness, | 106 | 265M | T: Clone, | 107 | | { | 108 | 265M | match tree { | 109 | 125M | FinalHuffmanTree::Leaf(ref value) => { | 110 | 125M | let len = queue.len(); | 111 | 125M | ReadHuffmanTree::Done(value.clone(), queue.value(), len, PhantomData) | 112 | | } | 113 | 140M | FinalHuffmanTree::Tree(ref bit0, ref bit1) => { | 114 | 140M | if queue.is_empty() { | 115 | | ReadHuffmanTree::Continue( | 116 | 274k | (0..256) | 117 | 274k | .map(|byte| compile_queue(BitQueue::from_value(byte as u8, 8), tree)) | 118 | 274k | .collect::<Vec<ReadHuffmanTree<E, T>>>() | 119 | 274k | .into_boxed_slice(), | 120 | | ) | 121 | 139M | } else if queue.pop(1) == 0 { | 122 | 69.9M | compile_queue(queue, bit0) | 123 | | } else { | 124 | 69.9M | compile_queue(queue, bit1) | 125 | | } | 126 | | } | 127 | | } | 128 | 265M | } |
Unexecuted instantiation: bitstream_io::huffman::compile_queue::<_, _> |
129 | | |
130 | | // A complete Huffman tree with no empty nodes |
131 | | enum FinalHuffmanTree<T: Clone> { |
132 | | Leaf(T), |
133 | | Tree(Box<FinalHuffmanTree<T>>, Box<FinalHuffmanTree<T>>), |
134 | | } |
135 | | |
136 | | impl<T: Clone> FinalHuffmanTree<T> { |
137 | 1.17M | fn new(values: Vec<(T, Vec<u8>)>) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> { |
138 | 1.17M | let mut tree = WipHuffmanTree::new_empty(); |
139 | | |
140 | 3.60M | for (symbol, code) in values { |
141 | 2.42M | tree.add(code.as_slice(), symbol)?; |
142 | | } |
143 | | |
144 | 1.17M | tree.into_read_tree() |
145 | 1.17M | } <bitstream_io::huffman::FinalHuffmanTree<u8>>::new Line | Count | Source | 137 | 960k | fn new(values: Vec<(T, Vec<u8>)>) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> { | 138 | 960k | let mut tree = WipHuffmanTree::new_empty(); | 139 | | | 140 | 2.88M | for (symbol, code) in values { | 141 | 1.92M | tree.add(code.as_slice(), symbol)?; | 142 | | } | 143 | | | 144 | 960k | tree.into_read_tree() | 145 | 960k | } |
<bitstream_io::huffman::FinalHuffmanTree<u16>>::new Line | Count | Source | 137 | 216k | fn new(values: Vec<(T, Vec<u8>)>) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> { | 138 | 216k | let mut tree = WipHuffmanTree::new_empty(); | 139 | | | 140 | 714k | for (symbol, code) in values { | 141 | 497k | tree.add(code.as_slice(), symbol)?; | 142 | | } | 143 | | | 144 | 216k | tree.into_read_tree() | 145 | 216k | } |
Unexecuted instantiation: <bitstream_io::huffman::FinalHuffmanTree<_>>::new |
146 | | } |
147 | | |
148 | | // Work-in-progress trees may have empty nodes during construction |
149 | | // but those are not allowed in a finalized tree. |
150 | | // If the user wants some codes to be None or an error symbol of some sort, |
151 | | // those will need to be specified explicitly. |
152 | | enum WipHuffmanTree<T: Clone> { |
153 | | Empty, |
154 | | Leaf(T), |
155 | | Tree(Box<WipHuffmanTree<T>>, Box<WipHuffmanTree<T>>), |
156 | | } |
157 | | |
158 | | impl<T: Clone> WipHuffmanTree<T> { |
159 | 3.67M | fn new_empty() -> WipHuffmanTree<T> { |
160 | 3.67M | WipHuffmanTree::Empty |
161 | 3.67M | } <bitstream_io::huffman::WipHuffmanTree<u8>>::new_empty Line | Count | Source | 159 | 2.89M | fn new_empty() -> WipHuffmanTree<T> { | 160 | 2.89M | WipHuffmanTree::Empty | 161 | 2.89M | } |
<bitstream_io::huffman::WipHuffmanTree<u16>>::new_empty Line | Count | Source | 159 | 779k | fn new_empty() -> WipHuffmanTree<T> { | 160 | 779k | WipHuffmanTree::Empty | 161 | 779k | } |
Unexecuted instantiation: <bitstream_io::huffman::WipHuffmanTree<_>>::new_empty |
162 | | |
163 | 2.42M | fn new_leaf(value: T) -> WipHuffmanTree<T> { |
164 | 2.42M | WipHuffmanTree::Leaf(value) |
165 | 2.42M | } <bitstream_io::huffman::WipHuffmanTree<u8>>::new_leaf Line | Count | Source | 163 | 1.92M | fn new_leaf(value: T) -> WipHuffmanTree<T> { | 164 | 1.92M | WipHuffmanTree::Leaf(value) | 165 | 1.92M | } |
<bitstream_io::huffman::WipHuffmanTree<u16>>::new_leaf Line | Count | Source | 163 | 497k | fn new_leaf(value: T) -> WipHuffmanTree<T> { | 164 | 497k | WipHuffmanTree::Leaf(value) | 165 | 497k | } |
Unexecuted instantiation: <bitstream_io::huffman::WipHuffmanTree<_>>::new_leaf |
166 | | |
167 | 1.24M | fn new_tree() -> WipHuffmanTree<T> { |
168 | 1.24M | WipHuffmanTree::Tree(Box::new(Self::new_empty()), Box::new(Self::new_empty())) |
169 | 1.24M | } <bitstream_io::huffman::WipHuffmanTree<u8>>::new_tree Line | Count | Source | 167 | 967k | fn new_tree() -> WipHuffmanTree<T> { | 168 | 967k | WipHuffmanTree::Tree(Box::new(Self::new_empty()), Box::new(Self::new_empty())) | 169 | 967k | } |
<bitstream_io::huffman::WipHuffmanTree<u16>>::new_tree Line | Count | Source | 167 | 281k | fn new_tree() -> WipHuffmanTree<T> { | 168 | 281k | WipHuffmanTree::Tree(Box::new(Self::new_empty()), Box::new(Self::new_empty())) | 169 | 281k | } |
Unexecuted instantiation: <bitstream_io::huffman::WipHuffmanTree<_>>::new_tree |
170 | | |
171 | 3.66M | fn into_read_tree(self) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> { |
172 | 3.66M | match self { |
173 | 513 | WipHuffmanTree::Empty => Err(HuffmanTreeError::MissingLeaf), |
174 | 2.41M | WipHuffmanTree::Leaf(v) => Ok(FinalHuffmanTree::Leaf(v)), |
175 | 1.24M | WipHuffmanTree::Tree(zero, one) => { |
176 | 1.24M | let zero = zero.into_read_tree()?; |
177 | 1.24M | let one = one.into_read_tree()?; |
178 | 1.24M | Ok(FinalHuffmanTree::Tree(Box::new(zero), Box::new(one))) |
179 | | } |
180 | | } |
181 | 3.66M | } <bitstream_io::huffman::WipHuffmanTree<u8>>::into_read_tree Line | Count | Source | 171 | 2.88M | fn into_read_tree(self) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> { | 172 | 2.88M | match self { | 173 | 382 | WipHuffmanTree::Empty => Err(HuffmanTreeError::MissingLeaf), | 174 | 1.92M | WipHuffmanTree::Leaf(v) => Ok(FinalHuffmanTree::Leaf(v)), | 175 | 965k | WipHuffmanTree::Tree(zero, one) => { | 176 | 965k | let zero = zero.into_read_tree()?; | 177 | 964k | let one = one.into_read_tree()?; | 178 | 963k | Ok(FinalHuffmanTree::Tree(Box::new(zero), Box::new(one))) | 179 | | } | 180 | | } | 181 | 2.88M | } |
<bitstream_io::huffman::WipHuffmanTree<u16>>::into_read_tree Line | Count | Source | 171 | 772k | fn into_read_tree(self) -> Result<FinalHuffmanTree<T>, HuffmanTreeError> { | 172 | 772k | match self { | 173 | 131 | WipHuffmanTree::Empty => Err(HuffmanTreeError::MissingLeaf), | 174 | 494k | WipHuffmanTree::Leaf(v) => Ok(FinalHuffmanTree::Leaf(v)), | 175 | 278k | WipHuffmanTree::Tree(zero, one) => { | 176 | 278k | let zero = zero.into_read_tree()?; | 177 | 277k | let one = one.into_read_tree()?; | 178 | 277k | Ok(FinalHuffmanTree::Tree(Box::new(zero), Box::new(one))) | 179 | | } | 180 | | } | 181 | 772k | } |
Unexecuted instantiation: <bitstream_io::huffman::WipHuffmanTree<_>>::into_read_tree |
182 | | |
183 | 8.76M | fn add(&mut self, code: &[u8], symbol: T) -> Result<(), HuffmanTreeError> { |
184 | 8.76M | match self { |
185 | | WipHuffmanTree::Empty => { |
186 | 3.67M | if code.is_empty() { |
187 | 2.42M | *self = WipHuffmanTree::new_leaf(symbol); |
188 | 2.42M | Ok(()) |
189 | | } else { |
190 | 1.24M | *self = WipHuffmanTree::new_tree(); |
191 | 1.24M | self.add(code, symbol) |
192 | | } |
193 | | } |
194 | 806 | WipHuffmanTree::Leaf(_) => Err(if code.is_empty() { |
195 | 574 | HuffmanTreeError::DuplicateLeaf |
196 | | } else { |
197 | 232 | HuffmanTreeError::OrphanedLeaf |
198 | | }), |
199 | 5.09M | WipHuffmanTree::Tree(ref mut zero, ref mut one) => { |
200 | 5.09M | if code.is_empty() { |
201 | 0 | Err(HuffmanTreeError::DuplicateLeaf) |
202 | | } else { |
203 | 5.09M | match code[0] { |
204 | 2.18M | 0 => zero.add(&code[1..], symbol), |
205 | 2.91M | 1 => one.add(&code[1..], symbol), |
206 | 0 | _ => Err(HuffmanTreeError::InvalidBit), |
207 | | } |
208 | | } |
209 | | } |
210 | | } |
211 | 8.76M | } <bitstream_io::huffman::WipHuffmanTree<u8>>::add Line | Count | Source | 183 | 6.47M | fn add(&mut self, code: &[u8], symbol: T) -> Result<(), HuffmanTreeError> { | 184 | 6.47M | match self { | 185 | | WipHuffmanTree::Empty => { | 186 | 2.89M | if code.is_empty() { | 187 | 1.92M | *self = WipHuffmanTree::new_leaf(symbol); | 188 | 1.92M | Ok(()) | 189 | | } else { | 190 | 967k | *self = WipHuffmanTree::new_tree(); | 191 | 967k | self.add(code, symbol) | 192 | | } | 193 | | } | 194 | 509 | WipHuffmanTree::Leaf(_) => Err(if code.is_empty() { | 195 | 320 | HuffmanTreeError::DuplicateLeaf | 196 | | } else { | 197 | 189 | HuffmanTreeError::OrphanedLeaf | 198 | | }), | 199 | 3.57M | WipHuffmanTree::Tree(ref mut zero, ref mut one) => { | 200 | 3.57M | if code.is_empty() { | 201 | 0 | Err(HuffmanTreeError::DuplicateLeaf) | 202 | | } else { | 203 | 3.57M | match code[0] { | 204 | 1.53M | 0 => zero.add(&code[1..], symbol), | 205 | 2.04M | 1 => one.add(&code[1..], symbol), | 206 | 0 | _ => Err(HuffmanTreeError::InvalidBit), | 207 | | } | 208 | | } | 209 | | } | 210 | | } | 211 | 6.47M | } |
<bitstream_io::huffman::WipHuffmanTree<u16>>::add Line | Count | Source | 183 | 2.29M | fn add(&mut self, code: &[u8], symbol: T) -> Result<(), HuffmanTreeError> { | 184 | 2.29M | match self { | 185 | | WipHuffmanTree::Empty => { | 186 | 779k | if code.is_empty() { | 187 | 497k | *self = WipHuffmanTree::new_leaf(symbol); | 188 | 497k | Ok(()) | 189 | | } else { | 190 | 281k | *self = WipHuffmanTree::new_tree(); | 191 | 281k | self.add(code, symbol) | 192 | | } | 193 | | } | 194 | 297 | WipHuffmanTree::Leaf(_) => Err(if code.is_empty() { | 195 | 254 | HuffmanTreeError::DuplicateLeaf | 196 | | } else { | 197 | 43 | HuffmanTreeError::OrphanedLeaf | 198 | | }), | 199 | 1.51M | WipHuffmanTree::Tree(ref mut zero, ref mut one) => { | 200 | 1.51M | if code.is_empty() { | 201 | 0 | Err(HuffmanTreeError::DuplicateLeaf) | 202 | | } else { | 203 | 1.51M | match code[0] { | 204 | 646k | 0 => zero.add(&code[1..], symbol), | 205 | 869k | 1 => one.add(&code[1..], symbol), | 206 | 0 | _ => Err(HuffmanTreeError::InvalidBit), | 207 | | } | 208 | | } | 209 | | } | 210 | | } | 211 | 2.29M | } |
Unexecuted instantiation: <bitstream_io::huffman::WipHuffmanTree<_>>::add |
212 | | } |
213 | | |
214 | | /// An error type during Huffman tree compilation. |
215 | | #[derive(PartialEq, Eq, Copy, Clone, Debug)] |
216 | | pub enum HuffmanTreeError { |
217 | | /// One of the bits in a Huffman code is not 0 or 1 |
218 | | InvalidBit, |
219 | | /// A Huffman code in the specification has no defined symbol |
220 | | MissingLeaf, |
221 | | /// The same Huffman code specifies multiple symbols |
222 | | DuplicateLeaf, |
223 | | /// A Huffman code is the prefix of some longer code |
224 | | OrphanedLeaf, |
225 | | } |
226 | | |
227 | | impl fmt::Display for HuffmanTreeError { |
228 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
229 | 0 | match *self { |
230 | 0 | HuffmanTreeError::InvalidBit => write!(f, "invalid bit in code"), |
231 | 0 | HuffmanTreeError::MissingLeaf => write!(f, "missing leaf node in specification"), |
232 | 0 | HuffmanTreeError::DuplicateLeaf => write!(f, "duplicate leaf node in specification"), |
233 | 0 | HuffmanTreeError::OrphanedLeaf => write!(f, "orphaned leaf node in specification"), |
234 | | } |
235 | 0 | } |
236 | | } |
237 | | |
238 | | impl std::error::Error for HuffmanTreeError {} |
239 | | |
240 | | /// Given a vector of symbol/code pairs, compiles a Huffman tree |
241 | | /// for writing. |
242 | | /// |
243 | | /// Code must be 0 or 1 bits and are always written to the stream |
244 | | /// from least-significant in the list to most signficant |
245 | | /// (which makes them easier to read for humans). |
246 | | /// |
247 | | /// If the same symbol occurs multiple times, the first code is used. |
248 | | /// Unlike in read trees, not all possible codes need to be |
249 | | /// assigned a symbol. |
250 | | /// |
251 | | /// ## Examples |
252 | | /// ``` |
253 | | /// use bitstream_io::huffman::compile_write_tree; |
254 | | /// use bitstream_io::BigEndian; |
255 | | /// assert!(compile_write_tree::<BigEndian,i32>( |
256 | | /// vec![(1, vec![0]), |
257 | | /// (2, vec![1, 0]), |
258 | | /// (3, vec![1, 1])]).is_ok()); |
259 | | /// ``` |
260 | | /// |
261 | | /// ``` |
262 | | /// use std::io::Write; |
263 | | /// use bitstream_io::{BigEndian, BitWriter, HuffmanWrite}; |
264 | | /// use bitstream_io::huffman::compile_write_tree; |
265 | | /// let tree = compile_write_tree( |
266 | | /// vec![('a', vec![0]), |
267 | | /// ('b', vec![1, 0]), |
268 | | /// ('c', vec![1, 1, 0]), |
269 | | /// ('d', vec![1, 1, 1])]).unwrap(); |
270 | | /// let mut data = Vec::new(); |
271 | | /// { |
272 | | /// let mut writer = BitWriter::endian(&mut data, BigEndian); |
273 | | /// writer.write_huffman(&tree, 'b').unwrap(); |
274 | | /// writer.write_huffman(&tree, 'c').unwrap(); |
275 | | /// writer.write_huffman(&tree, 'd').unwrap(); |
276 | | /// } |
277 | | /// assert_eq!(data, [0b10110111]); |
278 | | /// ``` |
279 | 0 | pub fn compile_write_tree<E, T>( |
280 | 0 | values: Vec<(T, Vec<u8>)>, |
281 | 0 | ) -> Result<WriteHuffmanTree<E, T>, HuffmanTreeError> |
282 | 0 | where |
283 | 0 | E: Endianness, |
284 | 0 | T: Ord + Clone, |
285 | | { |
286 | 0 | let mut map = BTreeMap::new(); |
287 | | |
288 | 0 | for (symbol, code) in values { |
289 | 0 | let mut encoded = Vec::new(); |
290 | 0 | for bits in code.chunks(32) { |
291 | 0 | let mut acc = BitQueue::<E, u32>::new(); |
292 | 0 | for bit in bits { |
293 | 0 | match *bit { |
294 | 0 | 0 => acc.push(1, 0), |
295 | 0 | 1 => acc.push(1, 1), |
296 | 0 | _ => return Err(HuffmanTreeError::InvalidBit), |
297 | | } |
298 | | } |
299 | 0 | let len = acc.len(); |
300 | 0 | encoded.push((len, acc.value())) |
301 | | } |
302 | 0 | map.entry(symbol) |
303 | 0 | .or_insert_with(|| encoded.into_boxed_slice()); |
304 | | } |
305 | | |
306 | 0 | Ok(WriteHuffmanTree { |
307 | 0 | map, |
308 | 0 | phantom: PhantomData, |
309 | 0 | }) |
310 | 0 | } |
311 | | |
312 | | /// A compiled Huffman tree for use with the `write_huffman` method. |
313 | | /// Returned by `compiled_write_tree`. |
314 | | pub struct WriteHuffmanTree<E: Endianness, T: Ord> { |
315 | | map: BTreeMap<T, Box<[(u32, u32)]>>, |
316 | | phantom: PhantomData<E>, |
317 | | } |
318 | | |
319 | | impl<E: Endianness, T: Ord + Clone> WriteHuffmanTree<E, T> { |
320 | | /// Returns true if symbol is in tree. |
321 | | #[inline] |
322 | 0 | pub fn has_symbol(&self, symbol: &T) -> bool { |
323 | 0 | self.map.contains_key(symbol) |
324 | 0 | } |
325 | | |
326 | | /// Given symbol, returns iterator of |
327 | | /// (bits, value) pairs for writing code. |
328 | | /// Panics if symbol is not found. |
329 | | #[inline] |
330 | 0 | pub fn get(&self, symbol: &T) -> impl Iterator<Item = &(u32, u32)> { |
331 | 0 | self.map[symbol].iter() |
332 | 0 | } |
333 | | } |