Coverage Report

Created: 2025-11-11 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}