From 26d6802bf02a042809d99115b390c1ae2dd0842c Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Sat, 12 Jun 2021 16:27:29 -0700 Subject: [PATCH] derive Clone on BitQueue, BitReader 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. --- src/lib.rs | 2 +- src/read.rs | 1 + tests/read.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index eba7ff0..4086fa8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 { phantom: PhantomData, value: N, diff --git a/src/read.rs b/src/read.rs index 289dda0..e1cf2df 100644 --- a/src/read.rs +++ b/src/read.rs @@ -201,6 +201,7 @@ pub trait HuffmanRead { /// 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 { reader: R, bitqueue: BitQueue, diff --git a/tests/read.rs b/tests/read.rs index 24af71d..626b63e 100644 --- a/tests/read.rs +++ b/tests/read.rs @@ -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::(4).unwrap(), 0xB); + let mut r2 = r.clone(); + assert!(!r.byte_aligned()); + assert_eq!(r.read::(4).unwrap(), 0x1); + assert_eq!(r.read::(8).unwrap(), 0xED); + assert!(!r2.byte_aligned()); + assert_eq!(r2.read::(4).unwrap(), 0x1); + assert_eq!(r2.read::(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 { + self.0.read(buf) + } + } + let _r = BitReader::endian(NotCloneRead(&actual_data[..]), BigEndian); +}