1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use nsw_types::u1;

pub trait BitRead: std::io::Read {
    /// Pull some bits from this source into the specified buffer, returning how many bytes were read.
    fn read_bits(&mut self, buf: &mut [u1]) -> std::io::Result<usize>;

    /// Read the exact number of bits required to fill buf.
    fn read_bits_exact(&mut self, buf: &mut [u1]) -> std::io::Result<()> {
        read_bits_exact_helper(self, buf)
    }
}

fn read_bits_exact_helper<R: BitRead + ?Sized>(
    this: &mut R,
    mut buf: &mut [u1],
) -> std::io::Result<()> {
    while !buf.is_empty() {
        // Note: unlike std::io::Read, we don't have a special case for an 'interrupted'
        // error, since we don't have access to all the error data it uses.
        // TODO: look into if we can replicate the is_interrupted logic here somehow.
        match this.read_bits(buf) {
            Ok(0) => break,
            Ok(n) => buf = &mut buf[n..],
            Err(e) => return Err(e),
        }
    }
    if !buf.is_empty() {
        Err(std::io::Error::new(
            std::io::ErrorKind::UnexpectedEof,
            "failed to fill whole buffer",
        ))
    } else {
        Ok(())
    }
}