Reading through a BitVec

I have to decode a data format with bit fields of various widths. BitVec looks like it will be a big help. But you can't read from a BitSlice. I need things that work like

let x1: u8 = bitstream.read(8).into(); // read 8 bits, put in x1
let x2: u16 = bitstream.read(12).into(); // read 12 bits, put in x2

as a sequential operation. It can all be done with indices, of course, but is there some crate that
already provides sequential access to a BitSlice.

Given bitvec's slice functionality, you can use the same trick std::io::Read does for &[u8] — that is, take a mutable reference to a slice reference and shorten it.

use bitvec::{
    field::BitField,
    order::{BitOrder, Lsb0},
    slice::BitSlice,
    store::BitStore,
    view::BitView,
};

fn read<'a, T: BitStore, O: BitOrder>(s: &mut &'a BitSlice<T, O>, n: usize) -> &'a BitSlice<T, O> {
    let result = &s[..n];
    *s = &s[n..];
    result
}

#[test]
fn t() {
    let mut bits = 0b101100111000_u64.view_bits::<Lsb0>();
    let pieces = [
        read(&mut bits, 6).load_le::<u8>(),
        read(&mut bits, 4).load_le::<u8>(),
        read(&mut bits, 2).load_le::<u8>(),
    ];
    assert_eq!(pieces, [0b111000, 0b1100, 0b10]);
}

I haven't actually used bitvec for this kind of work before (only used BitVec as a variable-size bitset) so the test case may be inelegant or wrong, but I hope it demonstrates the possibility.

1 Like

That works. I just had to add a result type so that it returns an error if you run off the end of the bitvec. Thanks.

I was thinking of something involving split_at but yours is more concise.

(Use case: decoding some rather tightly packed data that comes in via UDP from a game server.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.