bitstream_io/huffman.rs
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/// A trait for building a final value from individual bits
15///
16/// Though similar to the [`crate::read::FromBitStream`] trait,
17/// this is intended to parse short symbols from a stream of bits
18/// while `FromBitStream` is meant for parsing larger structs from
19/// a whole reader.
20/// For example, one might have several [`FromBits`] implementations
21/// in a single program that all generate `i32` symbols from bits,
22/// but implementing `FromBitStream` multiple times for `i32`
23/// isn't possible (or practical).
24pub trait FromBits {
25 /// Our returned symbol type
26 type Symbol;
27
28 /// Given a fallable bit generator, return our output type
29 ///
30 /// # Errors
31 ///
32 /// Passes along any error from the bit generator
33 fn from_bits<F, E>(next: F) -> Result<Self::Symbol, E>
34 where
35 F: FnMut() -> Result<bool, E>;
36}
37
38/// For building individual bits from a final value
39///
40/// Though similar to the [`crate::write::ToBitStream`] trait,
41/// this is intended to generate a stream of bits from short symbols
42/// while `ToBitStream` is meant for writing larger structs to
43/// a whole writer.
44/// For example, one might have several [`ToBits`] implementations
45/// in a single program that all write `i32` symbols to bits,
46/// but implementing `ToBitStream` multiple times for `i32`
47/// isn't possible (or practical).
48pub trait ToBits {
49 /// The type we accept to output
50 type Symbol;
51
52 /// Given a value to generate, write out bits as needed.
53 ///
54 /// Outputs nothing if the symbol isn't defined.
55 ///
56 /// # Errors
57 ///
58 /// Passes along any error from the bit generator
59 fn to_bits<F, E>(value: Self::Symbol, write: F) -> Result<(), E>
60 where
61 F: FnMut(bool) -> Result<(), E>;
62}
63
64/// Defines a new Huffman tree for reading and writing
65///
66/// Its syntax is: `define_huffman_tree!(name : type = nodes)`
67/// where `name` is some identifier to identify the tree in the
68/// macro's current scope, `type` is the tree's output
69/// type (which should implement `Copy` and `Eq`), and `nodes` is either a
70/// final leaf value or a `[bit_0, bit_1]` pair where `bit_0` is
71/// the tree visited on a `0` bit, and `bit_1` is the tree visited
72/// on a `1` bit.
73///
74/// # Example
75///
76/// ```
77/// use bitstream_io::{define_huffman_tree, huffman::FromBits};
78/// define_huffman_tree!(TreeName : &'static str = ["bit 0", ["bit 1->0", "bit 1->1"]]);
79/// let mut bits = [true, false].iter().copied();
80/// assert_eq!(TreeName::from_bits(|| bits.next().ok_or(())).unwrap(), "bit 1->0");
81/// ```
82#[macro_export]
83macro_rules! define_huffman_tree {
84 ($name:ident : $type:ty = $nodes:tt) => {
85 #[derive(Copy, Clone, Debug)]
86 struct $name;
87
88 impl $crate::huffman::FromBits for $name {
89 type Symbol = $type;
90
91 fn from_bits<F, E>(mut next: F) -> Result<Self::Symbol, E>
92 where
93 F: FnMut() -> Result<bool, E>,
94 {
95 $crate::compile_read_tree_nodes!(next, $nodes)
96 }
97 }
98
99 impl $crate::huffman::ToBits for $name {
100 type Symbol = $type;
101
102 fn to_bits<F, E>(value: Self::Symbol, mut write: F) -> Result<(), E>
103 where
104 F: FnMut(bool) -> Result<(), E>
105 {
106 $crate::compile_write_tree_nodes!(value ; write ; $nodes ; );
107 Ok(())
108 }
109 }
110 };
111}
112
113/// A helper macro for compiling individual Huffman tree nodes
114#[macro_export]
115macro_rules! compile_read_tree_nodes {
116 ($next:ident , [$bit_0:tt, $bit_1:tt]) => {
117 if $next()? {
118 $crate::compile_read_tree_nodes!($next, $bit_1)
119 } else {
120 $crate::compile_read_tree_nodes!($next, $bit_0)
121 }
122 };
123 ($next:ident , $final:tt) => {
124 Ok($final)
125 };
126}
127
128/// A helper macro for compiling individual Huffman tree nodes
129#[macro_export]
130macro_rules! compile_write_tree_nodes {
131 // end case for calculate tree node count
132 ($final:tt) => {
133 1
134 };
135 // recursive case for calculating tree node count
136 ([$bit_0:tt, $bit_1:tt]) => {
137 compile_write_tree_nodes!($bit_0) + compile_write_tree_nodes!($bit_1)
138 };
139 // entry point for generating conditional recursively
140 ($value:ident ; $write:ident ; [$bit_0:tt, $bit_1:tt] ; ) => {
141 if $crate::compile_write_tree_nodes!($bit_0) <= $crate::compile_write_tree_nodes!($bit_1) {
142 $crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; false);
143 $crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; true);
144 } else {
145 $crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; false);
146 $crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; true);
147 }
148 };
149 // recursive case for generating conditional
150 ($value:ident ; $write:ident ; [$bit_0:tt, $bit_1:tt] ; $($bits:tt),*) => {
151 if $crate::compile_write_tree_nodes!($bit_0) <= $crate::compile_write_tree_nodes!($bit_1) {
152 $crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; $($bits),* , false);
153 $crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; $($bits),* , true);
154 } else {
155 $crate::compile_write_tree_nodes!($value ; $write ; $bit_1 ; $($bits),* , false);
156 $crate::compile_write_tree_nodes!($value ; $write ; $bit_0 ; $($bits),* , true);
157 }
158 };
159 // final case for generating conditonal which generates bits
160 ($value:ident ; $write:ident ; $final:tt ; $( $bits:tt),* ) => {
161 if $value == $final {
162 $( $write($bits)?; )*
163 return Ok(());
164 }
165 };
166}
167
168/// A limited unary reader which stops at the given maximum.
169///
170/// Counts non-`STOP_BIT` values (which must be 0 or 1)
171/// until `STOP_BIT`, or until `MAXIMUM` is reached.
172/// Returns the number of non-`STOP_BIT` bits, or `None` if
173/// maximum is reached beforehand.
174///
175/// # Examples
176/// ```
177/// use bitstream_io::{BitReader, BitRead, BigEndian, huffman::LimitedUnary};
178///
179/// let data: &[u8] = &[0b001_00000, 0b1111_1111];
180/// let mut r = BitReader::endian(data, BigEndian);
181/// // get 2 bits until the next 1 bit
182/// assert_eq!(r.read_huffman::<LimitedUnary<1, 5>>().unwrap(), Some(2));
183/// // but 5 bits in a row is our maximum
184/// assert_eq!(r.read_huffman::<LimitedUnary<1, 5>>().unwrap(), None);
185/// // the remaining 8 bits are ok to be read
186/// assert_eq!(r.read::<8, u8>().unwrap(), 0b1111_1111);
187/// ```
188///
189/// ```
190/// use bitstream_io::{BitWriter, BitWrite, BigEndian, huffman::LimitedUnary};
191///
192/// let mut w = BitWriter::endian(vec![], BigEndian);
193/// // writes 2 as a regular unary value which stops at the 1 bit
194/// w.write_huffman::<LimitedUnary<1, 5>>(Some(2)).unwrap();
195/// // writing values beyond the maximum does nothing
196/// w.write_huffman::<LimitedUnary<1, 5>>(Some(10)).unwrap();
197/// // writes 5, 0 bits (which is our maximum)
198/// w.write_huffman::<LimitedUnary<1, 5>>(None).unwrap();
199/// // write some 1 bits to pad out the stream
200/// w.write::<8, u8>(0b1111_1111);
201///
202/// assert_eq!(w.into_writer(), &[0b001_00000, 0b1111_1111]);
203/// ```
204#[derive(Copy, Clone, Debug)]
205pub struct LimitedUnary<const STOP_BIT: u8, const MAXIMUM: u32>;
206
207impl<const STOP_BIT: u8, const MAXIMUM: u32> FromBits for LimitedUnary<STOP_BIT, MAXIMUM> {
208 type Symbol = Option<u32>;
209
210 fn from_bits<F, E>(mut next: F) -> Result<Self::Symbol, E>
211 where
212 F: FnMut() -> Result<bool, E>,
213 {
214 const {
215 assert!(matches!(STOP_BIT, 0 | 1), "stop bit must be 0 or 1");
216 }
217
218 let mut bits = 0;
219 while bits < MAXIMUM {
220 if next()?
221 != match STOP_BIT {
222 0 => false,
223 1 => true,
224 _ => unreachable!(),
225 }
226 {
227 bits += 1;
228 } else {
229 return Ok(Some(bits));
230 }
231 }
232 Ok(None)
233 }
234}
235
236impl<const STOP_BIT: u8, const MAXIMUM: u32> ToBits for LimitedUnary<STOP_BIT, MAXIMUM> {
237 type Symbol = Option<u32>;
238
239 fn to_bits<F, E>(value: Option<u32>, mut write: F) -> Result<(), E>
240 where
241 F: FnMut(bool) -> Result<(), E>,
242 {
243 const {
244 assert!(matches!(STOP_BIT, 0 | 1), "stop bit must be 0 or 1");
245 }
246
247 match value {
248 Some(bits) if bits < MAXIMUM => {
249 (0..bits).try_for_each(|_| {
250 write(match STOP_BIT {
251 0 => true,
252 1 => false,
253 _ => unreachable!(),
254 })
255 })?;
256 write(match STOP_BIT {
257 0 => false,
258 1 => true,
259 _ => unreachable!(),
260 })
261 }
262 Some(_) => {
263 /*more bits than MAXIMUM, so output nothing*/
264 Ok(())
265 }
266 None => (0..MAXIMUM).try_for_each(|_| {
267 write(match STOP_BIT {
268 0 => true,
269 1 => false,
270 _ => unreachable!(),
271 })
272 }),
273 }
274 }
275}