Skip to content

Commit b55f745

Browse files
committed
Huffman: Key invariant: highest weight bits are 0
1 parent b6c5727 commit b55f745

File tree

1 file changed

+51
-10
lines changed

1 file changed

+51
-10
lines changed

crates/binjs_io/src/context/huffman.rs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,64 @@ impl std::ops::Shl<BitLen> for u32 {
3535
}
3636
}
3737

38+
/// Convenience implementation of operator `>>` in
39+
/// `bits >> bit_len`
40+
impl std::ops::Shr<BitLen> for u32 {
41+
type Output = u32;
42+
fn shr(self, rhs: BitLen) -> u32 {
43+
self >> Into::<u8>::into(rhs)
44+
}
45+
}
46+
3847
/// The largerst acceptable length for a key.
3948
///
4049
/// Hardcoded in the format.
4150
const MAX_CODE_BIT_LENGTH: u8 = 20;
4251

52+
// privacy barrier
53+
mod key {
54+
use context::huffman::BitLen;
55+
4356
/// A Huffman key
4457
#[derive(Debug)]
45-
struct Key {
58+
pub struct Key {
4659
/// The bits in the key.
4760
///
4861
/// Note that we only use the `bit_len` lowest-weight bits.
49-
/// Any other bit is ignored.
62+
/// Any other bit MUST BE 0.
5063
bits: u32,
5164

5265
/// The number of bits of `bits` to use.
5366
bit_len: BitLen,
5467
}
68+
impl Key {
69+
/// Create a new Key.
70+
pub fn new(bits: u32, bit_len: BitLen) -> Self {
71+
debug_assert!({let bit_len : u8 = bit_len.into(); bit_len <= 32});
72+
debug_assert!({let bit_len : u8 = bit_len.into(); if bit_len < 32 { bits >> bit_len == 0 } else { true }});
73+
Key {
74+
bits,
75+
bit_len,
76+
}
77+
}
78+
79+
/// The bits in the key.
80+
///
81+
/// Note that we only use the `bit_len` lowest-weight bits.
82+
/// Any other bit is guaranteed to be 0.
83+
pub fn bits(&self) -> u32 {
84+
self.bits
85+
}
86+
87+
/// The number of bits of `bits` to use.
88+
pub fn bit_len(&self) -> BitLen {
89+
self.bit_len
90+
}
91+
}
92+
93+
} // mod key
94+
95+
use self::key::Key;
5596

5697
/// A node in the Huffman tree.
5798
struct Node<T> {
@@ -171,12 +212,12 @@ where
171212
bit_lengths[i].0.clone(),
172213
bit_lengths[i + 1].1,
173214
);
174-
keys.push((symbol.clone(), Key { bits, bit_len }));
215+
keys.push((symbol.clone(), Key::new(bits, bit_len)));
175216
bits = (bits + 1) << (next_bit_len - bit_len);
176217
}
177218
// Handle the last element.
178219
let (ref symbol, bit_len) = bit_lengths[bit_lengths.len() - 1];
179-
keys.push((symbol.clone(), Key { bits, bit_len }));
220+
keys.push((symbol.clone(), Key::new(bits, bit_len)));
180221

181222
return Ok(Self { keys });
182223
}
@@ -275,14 +316,14 @@ fn test_coded_from_sequence() {
275316
assert_eq!(coded.keys[2].0, 'l');
276317

277318
// Check bit length of symbols.
278-
assert_eq!(coded.keys[0].1.bit_len, 1.into());
279-
assert_eq!(coded.keys[1].1.bit_len, 2.into());
280-
assert_eq!(coded.keys[2].1.bit_len, 2.into());
319+
assert_eq!(coded.keys[0].1.bit_len(), 1.into());
320+
assert_eq!(coded.keys[1].1.bit_len(), 2.into());
321+
assert_eq!(coded.keys[2].1.bit_len(), 2.into());
281322

282323
// Check code of symbols.
283-
assert_eq!(coded.keys[0].1.bits, 0b00);
284-
assert_eq!(coded.keys[1].1.bits, 0b10);
285-
assert_eq!(coded.keys[2].1.bits, 0b11);
324+
assert_eq!(coded.keys[0].1.bits(), 0b00);
325+
assert_eq!(coded.keys[1].1.bits(), 0b10);
326+
assert_eq!(coded.keys[2].1.bits(), 0b11);
286327

287328
// Let's try again with a limit to 1 bit paths.
288329
assert_eq!(Keys::from_sequence(sample.chars(), 1).unwrap_err(), 2);

0 commit comments

Comments
 (0)