Skip to content

Commit

Permalink
derive Clone on BitQueue, BitReader
Browse files Browse the repository at this point in the history
This is useful for querying the position within a H.264 bitstream
relative to the final one bit; details in dholroyd/h264-reader#28.

The default #![derive(Clone)] behavior is nice: BitReader will be
Clone iff the backing std::io::Read is also Clone. Out of paranoia,
I added a test that clone works properly and that it's still possible
to instantiate a BitReader with a non-Clone R.
  • Loading branch information
scottlamb committed Jun 13, 2021
1 parent b024a94 commit 26d6802
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ impl Endianness for LittleEndian {

/// A queue for efficiently pushing bits onto a value
/// and popping them off a value.
#[derive(Default)]
#[derive(Clone, Default)]
pub struct BitQueue<E: Endianness, N: Numeric> {
phantom: PhantomData<E>,
value: N,
Expand Down
1 change: 1 addition & 0 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ pub trait HuffmanRead<E: Endianness> {
/// This will read exactly as many whole bytes needed to return
/// the requested number of bits. It may cache up to a single partial byte
/// but no more.
#[derive(Clone)]
pub struct BitReader<R: io::Read, E: Endianness> {
reader: R,
bitqueue: BitQueue<E, u8>,
Expand Down
28 changes: 28 additions & 0 deletions tests/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,3 +617,31 @@ fn test_reader_bits_errors() {
ErrorKind::InvalidInput
);
}

#[test]
fn test_clone() {
use bitstream_io::{BigEndian, BitRead, BitReader};

// Reading unsigned examples, cloning while unaligned.
let actual_data: [u8; 4] = [0xB1, 0xED, 0x3B, 0xC1];
let mut r = BitReader::endian(Cursor::new(&actual_data), BigEndian);
assert!(r.byte_aligned());
assert_eq!(r.read::<u32>(4).unwrap(), 0xB);
let mut r2 = r.clone();
assert!(!r.byte_aligned());
assert_eq!(r.read::<u32>(4).unwrap(), 0x1);
assert_eq!(r.read::<u32>(8).unwrap(), 0xED);
assert!(!r2.byte_aligned());
assert_eq!(r2.read::<u32>(4).unwrap(), 0x1);
assert_eq!(r2.read::<u32>(8).unwrap(), 0xED);

// Can still instantiate a BitReader when the backing std::io::Read is
// !Clone.
struct NotCloneRead<'a>(&'a [u8]);
impl<'a> std::io::Read for NotCloneRead<'a> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.0.read(buf)
}
}
let _r = BitReader::endian(NotCloneRead(&actual_data[..]), BigEndian);
}

0 comments on commit 26d6802

Please sign in to comment.