I was wondering if there’s a more idiomatic way to implement the following code. It’s part of a compression library, and interleaves bits from one vector into another wherever placeholders are found. The use of an ‘if’ to select one of two prebuilt Bit()s, and the use of ‘q’ to index into arith_bits, both seem quite clumsy to me. Also, arith_bits is never used again, so perhaps I should be moving it out of self then draining it?
Not sure whether the map-{if-let}-before-match I used to avoid duplicating the Bit() processing logic is the sanest approach either. Any thoughts?
enum StreamSymbol {
Byte(u8),
Bit(u8),
ArithPlaceholder,
}
struct Encoder {
output_stream: Vec<StreamSymbol>,
arith_bits: Vec<u8>,
denom: u8,
}
impl Encoder {
fn collapse_stream(&mut self) -> Vec<u8> {
let mut nbits = 8;
let mut bits_index = 0;
{
// propagate carries in numerator accumulator
let mut acc = 0;
for e in self.arith_bits.iter_mut().rev() {
assert!(255 - *e >= acc);
acc += *e;
*e = acc & 1;
acc >>= 1;
}
self.arith_bits[0] += acc * 2;
}
let mut res: Vec<u8> = vec![self.arith_bits[0]];
let mut q = 0;
for i in self.output_stream.iter().map(|i| {
if let StreamSymbol::ArithPlaceholder = i {
q = q + 1;
if self.arith_bits[q] == 0 {
&StreamSymbol::Bit(0)
} else {
&StreamSymbol::Bit(1)
}
} else {
i
}
}) {
match i {
StreamSymbol::Byte(i) => res.push(*i),
StreamSymbol::Bit(b) => {
if nbits == 8 {
nbits = 0;
bits_index = res.len();
res.push(0);
}
res[bits_index] += b << (7 - nbits);
nbits += 1;
}
StreamSymbol::ArithPlaceholder => {
assert!(false);
}
}
}
res
}
}