/rust/registry/src/index.crates.io-1949cf8c6b5b557f/bitstream-io-4.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 | | /// 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). |
24 | | pub 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). |
48 | | pub 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] |
83 | | macro_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] |
115 | | macro_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] |
130 | | macro_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)] |
205 | | pub struct LimitedUnary<const STOP_BIT: u8, const MAXIMUM: u32>; |
206 | | |
207 | | impl<const STOP_BIT: u8, const MAXIMUM: u32> FromBits for LimitedUnary<STOP_BIT, MAXIMUM> { |
208 | | type Symbol = Option<u32>; |
209 | | |
210 | 0 | fn from_bits<F, E>(mut next: F) -> Result<Self::Symbol, E> |
211 | 0 | where |
212 | 0 | 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 | 0 | let mut bits = 0; |
219 | 0 | while bits < MAXIMUM { |
220 | 0 | if next()? |
221 | 0 | != match STOP_BIT { |
222 | 0 | 0 => false, |
223 | 0 | 1 => true, |
224 | 0 | _ => unreachable!(), |
225 | | } |
226 | 0 | { |
227 | 0 | bits += 1; |
228 | 0 | } else { |
229 | 0 | return Ok(Some(bits)); |
230 | | } |
231 | | } |
232 | 0 | Ok(None) |
233 | 0 | } |
234 | | } |
235 | | |
236 | | impl<const STOP_BIT: u8, const MAXIMUM: u32> ToBits for LimitedUnary<STOP_BIT, MAXIMUM> { |
237 | | type Symbol = Option<u32>; |
238 | | |
239 | 0 | fn to_bits<F, E>(value: Option<u32>, mut write: F) -> Result<(), E> |
240 | 0 | where |
241 | 0 | 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 | 0 | match value { |
248 | 0 | Some(bits) if bits < MAXIMUM => { |
249 | 0 | (0..bits).try_for_each(|_| { |
250 | 0 | write(match STOP_BIT { |
251 | 0 | 0 => true, |
252 | 0 | 1 => false, |
253 | 0 | _ => unreachable!(), |
254 | | }) |
255 | 0 | })?; |
256 | 0 | write(match STOP_BIT { |
257 | 0 | 0 => false, |
258 | 0 | 1 => true, |
259 | 0 | _ => unreachable!(), |
260 | | }) |
261 | | } |
262 | | Some(_) => { |
263 | | /*more bits than MAXIMUM, so output nothing*/ |
264 | 0 | Ok(()) |
265 | | } |
266 | 0 | None => (0..MAXIMUM).try_for_each(|_| { |
267 | 0 | write(match STOP_BIT { |
268 | 0 | 0 => true, |
269 | 0 | 1 => false, |
270 | 0 | _ => unreachable!(), |
271 | | }) |
272 | 0 | }), |
273 | | } |
274 | 0 | } |
275 | | } |