1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 08:34:07 +02:00

make write stream borrow the data to allow splitting/reserving

This commit is contained in:
Robin Appelman 2021-07-14 23:35:13 +02:00
commit 9bced05a9d
6 changed files with 480 additions and 126 deletions

View file

@ -50,9 +50,10 @@ fn test_read_struct() {
asd: 0b101, asd: 0b101,
previous_field: 0b1010_0, previous_field: 0b1010_0,
}; };
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write(&val).unwrap(); stream.write(&val).unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }
#[derive(BitWrite, PartialEq, Debug)] #[derive(BitWrite, PartialEq, Debug)]
@ -66,12 +67,13 @@ enum TestBareEnum {
#[test] #[test]
fn test_read_bare_enum() { fn test_read_bare_enum() {
let bytes = vec![0b1100_0100]; let bytes = vec![0b1100_0100];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream.write(&TestBareEnum::Asd).unwrap(); stream.write(&TestBareEnum::Asd).unwrap();
stream.write(&TestBareEnum::Foo).unwrap(); stream.write(&TestBareEnum::Foo).unwrap();
stream.write(&TestBareEnum::Bar).unwrap(); stream.write(&TestBareEnum::Bar).unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }
#[derive(BitWrite, BitRead, PartialEq, Debug)] #[derive(BitWrite, BitRead, PartialEq, Debug)]
@ -87,7 +89,8 @@ enum TestUnnamedFieldEnum {
#[test] #[test]
fn test_read_unnamed_field_enum() { fn test_read_unnamed_field_enum() {
let bytes = vec![0b1100_0110, 0b1000_0110, 0b1011_0000]; let bytes = vec![0b1100_0110, 0b1000_0110, 0b1011_0000];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream stream
.write(&TestUnnamedFieldEnum::Asd(0b_00_0110_10)) .write(&TestUnnamedFieldEnum::Asd(0b_00_0110_10))
.unwrap(); .unwrap();
@ -98,8 +101,7 @@ fn test_read_unnamed_field_enum() {
stream.write(&TestUnnamedFieldEnum::Bar(true)).unwrap(); stream.write(&TestUnnamedFieldEnum::Bar(true)).unwrap();
let result = stream.finish(); let mut read = BitReadStream::<BigEndian>::from(data.as_slice());
let mut read = BitReadStream::<BigEndian>::from(result.as_slice());
assert_eq!( assert_eq!(
TestUnnamedFieldEnum::Asd(0b_00_0110_10), TestUnnamedFieldEnum::Asd(0b_00_0110_10),
@ -108,7 +110,7 @@ fn test_read_unnamed_field_enum() {
assert_eq!(TestUnnamedFieldEnum::Foo(0b11_0_1), read.read().unwrap()); assert_eq!(TestUnnamedFieldEnum::Foo(0b11_0_1), read.read().unwrap());
assert_eq!(TestUnnamedFieldEnum::Bar(true), read.read().unwrap()); assert_eq!(TestUnnamedFieldEnum::Bar(true), read.read().unwrap());
assert_eq!(bytes, result); assert_eq!(bytes, data);
} }
#[derive(BitWriteSized, BitReadSized, PartialEq, Debug)] #[derive(BitWriteSized, BitReadSized, PartialEq, Debug)]
@ -123,19 +125,19 @@ struct TestStructSized {
#[test] #[test]
fn test_read_struct_sized() { fn test_read_struct_sized() {
let bytes = vec![12, 'h' as u8, 'e' as u8, 'l' as u8, 0b1000_0000]; let bytes = vec![12, 'h' as u8, 'e' as u8, 'l' as u8, 0b1000_0000];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
let val = TestStructSized { let val = TestStructSized {
foo: 12, foo: 12,
string: "hel".to_owned(), string: "hel".to_owned(),
int: 4, int: 4,
}; };
stream.write_sized(&val, 3).unwrap(); stream.write_sized(&val, 3).unwrap();
let result = stream.finish(); let mut read = BitReadStream::<BigEndian>::from(data.as_slice());
let mut read = BitReadStream::<BigEndian>::from(result.as_slice());
assert_eq!(val, read.read_sized(3).unwrap()); assert_eq!(val, read.read_sized(3).unwrap());
assert_eq!(bytes, result); assert_eq!(bytes, data);
} }
#[derive(BitWriteSized, PartialEq, Debug)] #[derive(BitWriteSized, PartialEq, Debug)]
@ -152,11 +154,12 @@ enum TestUnnamedFieldEnumSized {
#[test] #[test]
fn test_read_unnamed_field_enum_sized() { fn test_read_unnamed_field_enum_sized() {
let bytes = vec![0b1100_0110]; let bytes = vec![0b1100_0110];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream stream
.write_sized(&TestUnnamedFieldEnumSized::Asd(0b_00_0110), 6) .write_sized(&TestUnnamedFieldEnumSized::Asd(0b_00_0110), 6)
.unwrap(); .unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }
#[derive(BitWrite, PartialEq, Debug)] #[derive(BitWrite, PartialEq, Debug)]
@ -181,14 +184,15 @@ fn test_read_struct2() {
'r' as u8, 'r' as u8,
'l' as u8, 'l' as u8,
]; ];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream stream
.write(&TestStruct2 { .write(&TestStruct2 {
size: 5, size: 5,
str: "hello worl".to_owned(), str: "hello worl".to_owned(),
}) })
.unwrap(); .unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }
#[derive(BitWrite)] #[derive(BitWrite)]
@ -202,7 +206,8 @@ struct TestStruct3<'a, E: Endianness> {
#[test] #[test]
fn test_read_struct3() { fn test_read_struct3() {
let bytes = vec![0b0000_0101, 0b1010_1000]; let bytes = vec![0b0000_0101, 0b1010_1000];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
let mut inner = BitReadStream::from(BitReadBuffer::new(&[0b1010_1010], BigEndian)); let mut inner = BitReadStream::from(BitReadBuffer::new(&[0b1010_1010], BigEndian));
let inner = inner.read_bits(5).unwrap(); let inner = inner.read_bits(5).unwrap();
@ -212,7 +217,7 @@ fn test_read_struct3() {
stream: inner, stream: inner,
}; };
stream.write(&val).unwrap(); stream.write(&val).unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }
#[derive(BitWrite, PartialEq, Debug)] #[derive(BitWrite, PartialEq, Debug)]
@ -227,14 +232,15 @@ enum TestEnumRest {
#[test] #[test]
fn test_read_rest_enum() { fn test_read_rest_enum() {
let bytes = vec![0b1000_0110]; let bytes = vec![0b1000_0110];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream.write(&TestEnumRest::Asd).unwrap(); stream.write(&TestEnumRest::Asd).unwrap();
stream.write(&TestEnumRest::Foo).unwrap(); stream.write(&TestEnumRest::Foo).unwrap();
stream.write(&TestEnumRest::Bar).unwrap(); stream.write(&TestEnumRest::Bar).unwrap();
stream.write(&TestEnumRest::Asd).unwrap(); stream.write(&TestEnumRest::Asd).unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }
#[derive(BitWrite, PartialEq, Debug)] #[derive(BitWrite, PartialEq, Debug)]
@ -244,21 +250,23 @@ fn test_unnamed_struct() {
let bytes = vec![ let bytes = vec![
12, 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0, 0, 0, 0, 0, 0, 12, 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, 0, 0, 0, 0, 0, 0,
]; ];
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream stream
.write(&UnnamedSize(12, "hello".to_string(), false)) .write(&UnnamedSize(12, "hello".to_string(), false))
.unwrap(); .unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }
#[derive(BitWrite, PartialEq, Debug)] #[derive(BitWrite, PartialEq, Debug)]
struct EmptyStruct; struct EmptyStruct;
fn test_empty_struct() { fn test_empty_struct() {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write(&EmptyStruct).unwrap(); stream.write(&EmptyStruct).unwrap();
assert_eq!(Vec::<u8>::new(), stream.finish()); assert_eq!(Vec::<u8>::new(), data);
} }
#[derive(BitWrite)] #[derive(BitWrite)]
@ -271,12 +279,13 @@ struct TestSizeExpression {
#[test] #[test]
fn test_read_size_expression() { fn test_read_size_expression() {
let bytes = vec![0b0000_0011, b'a', b'b', b'c', b'd', b'e']; let bytes = vec![0b0000_0011, b'a', b'b', b'c', b'd', b'e'];
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
let val = TestSizeExpression { let val = TestSizeExpression {
size: 3, size: 3,
str: String::from("abcde"), str: String::from("abcde"),
}; };
stream.write(&val).unwrap(); stream.write(&val).unwrap();
assert_eq!(bytes, stream.finish()); assert_eq!(bytes, data);
} }

View file

@ -72,6 +72,7 @@ mod read;
mod readbuffer; mod readbuffer;
mod readstream; mod readstream;
mod write; mod write;
mod writebuffer;
mod writestream; mod writestream;
/// Errors that can be returned when trying to read from a buffer /// Errors that can be returned when trying to read from a buffer

381
src/writebuffer.rs Normal file
View file

@ -0,0 +1,381 @@
use crate::Endianness;
use std::cmp::min;
use std::iter::{once, repeat};
use std::marker::PhantomData;
use std::mem::size_of;
const USIZE_BITS: usize = size_of::<usize>() * 8;
pub struct WriteBuffer<'a, E: Endianness>(CowWriteBuffer<'a, E>);
impl<'a, E: Endianness> WriteBuffer<'a, E> {
pub fn new(bytes: &'a mut Vec<u8>, endianness: E) -> Self {
WriteBuffer(CowWriteBuffer::ExpandBorrowed(ExpandWriteBuffer::new(
bytes, endianness,
)))
}
/// The number of written bits in the buffer
pub fn bit_len(&self) -> usize {
self.0.bit_len()
}
pub fn push_non_fit_bits<I>(&mut self, bits: I, count: usize)
where
I: ExactSizeIterator,
I: DoubleEndedIterator<Item = u8>,
{
let full_bytes = min(bits.len() - 1, count / 8);
let counts = repeat(8)
.take(full_bytes)
.chain(once(count - full_bytes * 8));
if E::is_le() {
bits.zip(counts)
.for_each(|(chunk, count)| self.push_bits(chunk as usize, count))
} else {
bits.take(count / 8 + 1)
.rev()
.zip(counts)
.for_each(|(chunk, count)| self.push_bits(chunk as usize, count))
}
}
/// Push up to an usize worth of bits
pub fn push_bits(&mut self, bits: usize, count: usize) {
self.0.push_bits(bits, count)
}
pub fn reserve(&mut self, length: usize) -> (WriteBuffer<E>, WriteBuffer<E>) {
let (head, tail) = self.0.reserve(length);
(WriteBuffer(head), WriteBuffer(tail))
}
}
enum CowWriteBuffer<'a, E: Endianness> {
FixedBorrowed(FixedWriteBuffer<'a, E>),
ExpandBorrowed(ExpandWriteBuffer<'a, E>),
}
impl<'a, E: Endianness> CowWriteBuffer<'a, E> {
/// The number of written bits in the buffer
fn bit_len(&self) -> usize {
match self {
CowWriteBuffer::FixedBorrowed(buffer) => buffer.bit_len(),
CowWriteBuffer::ExpandBorrowed(buffer) => buffer.bit_len(),
}
}
/// Push up to an usize worth of bits
fn push_bits(&mut self, bits: usize, count: usize) {
match self {
CowWriteBuffer::FixedBorrowed(buffer) => buffer.push_bits(bits, count),
CowWriteBuffer::ExpandBorrowed(buffer) => buffer.push_bits(bits, count),
}
}
/// Reserve some bits to be written later by splitting of two parts
fn reserve(&mut self, length: usize) -> (CowWriteBuffer<E>, CowWriteBuffer<E>) {
match self {
CowWriteBuffer::FixedBorrowed(buffer) => {
let (head, tail) = buffer.reserve(length);
(
CowWriteBuffer::FixedBorrowed(head),
CowWriteBuffer::FixedBorrowed(tail),
)
}
CowWriteBuffer::ExpandBorrowed(buffer) => {
let (head, tail) = buffer.reserve(length);
(
CowWriteBuffer::FixedBorrowed(head),
CowWriteBuffer::ExpandBorrowed(tail),
)
}
}
}
}
struct ExpandWriteBuffer<'a, E: Endianness> {
bit_len: usize,
bytes: &'a mut Vec<u8>,
endianness: PhantomData<E>,
}
impl<'a, E: Endianness> ExpandWriteBuffer<'a, E> {
fn new(bytes: &'a mut Vec<u8>, _endianness: E) -> Self {
ExpandWriteBuffer {
bit_len: 0,
bytes,
endianness: PhantomData,
}
}
/// The number of written bits in the buffer
fn bit_len(&self) -> usize {
self.bit_len
}
/// Push up to an usize worth of bits
fn push_bits(&mut self, bits: usize, count: usize) {
debug_assert!(count < USIZE_BITS - 8);
// ensure there are no stray bits
let bits = bits & (usize::MAX >> (USIZE_BITS - count));
let bit_offset = self.bit_len & 7;
let last_written_byte = if bit_offset > 0 {
self.bytes.pop().unwrap_or(0)
} else {
0
};
let merged_byte_count = (count + bit_offset + 7) / 8;
if E::is_le() {
let merged = last_written_byte as usize | bits << bit_offset;
self.bytes
.extend_from_slice(&merged.to_le_bytes()[0..merged_byte_count]);
} else {
let merged = ((last_written_byte as usize) << (USIZE_BITS - 8))
| (bits << (USIZE_BITS - bit_offset - count));
self.bytes
.extend_from_slice(&merged.to_be_bytes()[0..merged_byte_count]);
}
self.bit_len += count;
}
/// Reserve some bits to be written later by splitting of two parts
///
/// One fixed size part and one expanding part
fn reserve(&mut self, length: usize) -> (FixedWriteBuffer<E>, ExpandWriteBuffer<E>) {
let byte_count = (length + 7) / 8;
let bit_offset = self.bit_len & 7;
let byte_index = self.bit_len / 8;
let end_byte = byte_index + byte_count;
self.bytes.resize(end_byte, 0);
self.bit_len += length;
// take a mut slice without telling the borrow checker
// this is safe because
// 1. the buffers are append only, meaning that the "expand" part can't mess with the reserved bits
// 2. the underlying vec can only be used again after both parts have been dropped
let bytes = unsafe {
let ptr = self.bytes[byte_index..end_byte].as_mut_ptr();
std::slice::from_raw_parts_mut(ptr, byte_count)
};
(
FixedWriteBuffer::new(bytes, bit_offset, length + bit_offset, E::endianness()),
ExpandWriteBuffer {
bit_len: self.bit_len,
bytes: self.bytes,
endianness: PhantomData,
},
)
}
}
#[test]
fn test_push_expand_be() {
use crate::BigEndian;
let mut buffer = vec![];
let mut write = ExpandWriteBuffer::new(&mut buffer, BigEndian);
write.push_bits(0b1101, 4);
write.push_bits(0b1, 1);
write.push_bits(0b0, 1);
write.push_bits(0b101_01010, 8);
assert_eq!(vec![0b1101_1_0_10, 0b101010_00], buffer)
}
#[test]
fn test_push_expand_le() {
use crate::LittleEndian;
let mut buffer = vec![];
let mut write = ExpandWriteBuffer::new(&mut buffer, LittleEndian);
write.push_bits(0b1101, 4);
write.push_bits(0b1, 1);
write.push_bits(0b0, 1);
write.push_bits(0b101_01010, 8);
assert_eq!(vec![0b10_0_1_1101, 0b00101010], buffer)
}
#[test]
fn test_push_expand_reserve_be() {
use crate::BigEndian;
let mut buffer = vec![];
let mut write = ExpandWriteBuffer::new(&mut buffer, BigEndian);
write.push_bits(0b1101, 4);
let (mut reserved, mut rest) = write.reserve(2);
rest.push_bits(0b101_01010, 8);
reserved.push_bits(0b1, 1);
reserved.push_bits(0b0, 1);
assert_eq!(vec![0b1101_1_0_10, 0b101010_00], buffer)
}
#[test]
fn test_push_expand_reserve_le() {
use crate::LittleEndian;
let mut buffer = vec![];
let mut write = ExpandWriteBuffer::new(&mut buffer, LittleEndian);
write.push_bits(0b1101, 4);
let (mut reserved, mut rest) = write.reserve(2);
rest.push_bits(0b101_01010, 8);
reserved.push_bits(0b1, 1);
reserved.push_bits(0b0, 1);
assert_eq!(vec![0b10_0_1_1101, 0b00101010], buffer)
}
struct FixedWriteBuffer<'a, E: Endianness> {
bit_start: usize,
bit_len: usize,
bytes: &'a mut [u8],
endianness: PhantomData<E>,
bit_size: usize,
}
impl<'a, E: Endianness> FixedWriteBuffer<'a, E> {
fn new(bytes: &'a mut [u8], bit_start: usize, bit_size: usize, _endianness: E) -> Self {
FixedWriteBuffer {
bit_start,
bit_len: bit_start,
bytes,
endianness: PhantomData,
bit_size,
}
}
/// The number of written bits in the buffer
fn bit_len(&self) -> usize {
self.bit_len - self.bit_start
}
/// Push up to an usize worth of bits
fn push_bits(&mut self, bits: usize, count: usize) {
debug_assert!(count < USIZE_BITS - 8);
assert!(self.bit_len + count <= self.bit_size);
// ensure there are no stray bits
let bits = bits & (usize::MAX >> (USIZE_BITS - count));
let bit_offset = self.bit_len & 7;
let byte_index = self.bit_len / 8;
let last_written_byte = self.bytes[byte_index];
let merged_byte_count = (count + bit_offset + 7) / 8;
if E::is_le() {
let merged = last_written_byte as usize | bits << bit_offset;
self.bytes[byte_index..byte_index + merged_byte_count]
.copy_from_slice(&merged.to_le_bytes()[0..merged_byte_count]);
} else {
let merged = ((last_written_byte as usize) << (USIZE_BITS - 8))
| (bits << (USIZE_BITS - bit_offset - count));
self.bytes[byte_index..byte_index + merged_byte_count]
.copy_from_slice(&merged.to_be_bytes()[0..merged_byte_count]);
}
self.bit_len += count;
}
fn reserve(&mut self, length: usize) -> (FixedWriteBuffer<E>, FixedWriteBuffer<E>) {
assert!(self.bit_len + length <= self.bit_size);
let byte_count = (length + 7) / 8;
let bit_offset = self.bit_len & 7;
let byte_index = self.bit_len / 8;
self.bit_len += length;
// take a mut slice without telling the borrow checker
// this is safe because
// 1. the buffers are append only, meaning that the last part can't mess with the reserved bits
// 2. the underlying vec can only be used again after both parts have been dropped
let bytes = unsafe {
let ptr = self.bytes[byte_index..byte_count + byte_count].as_mut_ptr();
std::slice::from_raw_parts_mut(ptr, byte_count)
};
(
FixedWriteBuffer::new(bytes, bit_offset, length + bit_offset, E::endianness()),
FixedWriteBuffer::new(self.bytes, self.bit_len, self.bit_size, E::endianness()),
)
}
}
#[test]
fn test_push_fixed_be() {
use crate::BigEndian;
let mut buffer = vec![0; 2];
let mut write = FixedWriteBuffer::new(&mut buffer, 0, 16, BigEndian);
write.push_bits(0b1101, 4);
assert_eq!(4, write.bit_len());
write.push_bits(0b1, 1);
assert_eq!(5, write.bit_len());
write.push_bits(0b0, 1);
assert_eq!(6, write.bit_len());
write.push_bits(0b101_01010, 8);
assert_eq!(vec![0b1101_1_0_10, 0b101010_00], buffer)
}
#[test]
fn test_push_fixed_le() {
use crate::LittleEndian;
let mut buffer = vec![0; 2];
let mut write = FixedWriteBuffer::new(&mut buffer, 0, 16, LittleEndian);
write.push_bits(0b1101, 4);
assert_eq!(4, write.bit_len());
write.push_bits(0b1, 1);
assert_eq!(5, write.bit_len());
write.push_bits(0b0, 1);
assert_eq!(6, write.bit_len());
write.push_bits(0b101_01010, 8);
assert_eq!(vec![0b10_0_1_1101, 0b00101010], buffer)
}
#[test]
fn test_push_fixed_reserve_be() {
use crate::BigEndian;
let mut buffer = vec![0; 2];
let mut write = FixedWriteBuffer::new(&mut buffer, 0, 16, BigEndian);
write.push_bits(0b1101, 4);
let (mut reserved, mut rest) = write.reserve(2);
rest.push_bits(0b101_01010, 8);
reserved.push_bits(0b1, 1);
reserved.push_bits(0b0, 1);
assert_eq!(vec![0b1101_1_0_10, 0b101010_00], buffer)
}
#[test]
fn test_push_fixed_reserve_le() {
use crate::LittleEndian;
let mut buffer = vec![0; 2];
let mut write = FixedWriteBuffer::new(&mut buffer, 0, 16, LittleEndian);
write.push_bits(0b1101, 4);
let (mut reserved, mut rest) = write.reserve(2);
rest.push_bits(0b101_01010, 8);
reserved.push_bits(0b1, 1);
reserved.push_bits(0b0, 1);
assert_eq!(vec![0b10_0_1_1101, 0b00101010], buffer)
}

View file

@ -1,13 +1,11 @@
use num_traits::{Float, PrimInt}; use num_traits::{Float, PrimInt};
use std::iter::{once, repeat};
use std::marker::PhantomData;
use std::mem::size_of; use std::mem::size_of;
use std::ops::{BitOrAssign, BitXor}; use std::ops::{BitOrAssign, BitXor};
use crate::endianness::Endianness; use crate::endianness::Endianness;
use crate::num_traits::{IntoBytes, IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt}; use crate::num_traits::{IntoBytes, IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::writebuffer::WriteBuffer;
use crate::{BitError, BitReadStream, BitWrite, BitWriteSized, Result}; use crate::{BitError, BitReadStream, BitWrite, BitWriteSized, Result};
use std::cmp::min;
use std::fmt::Debug; use std::fmt::Debug;
const USIZE_SIZE: usize = size_of::<usize>(); const USIZE_SIZE: usize = size_of::<usize>();
@ -22,7 +20,8 @@ const USIZE_BITS: usize = USIZE_SIZE * 8;
/// # use bitbuffer::Result; /// # use bitbuffer::Result;
/// ///
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// let mut stream = BitWriteStream::new(LittleEndian); /// let mut data = Vec::new();
/// let mut stream = BitWriteStream::new(&mut data, LittleEndian);
/// ///
/// stream.write_bool(false)?; /// stream.write_bool(false)?;
/// stream.write_int(123u16, 15)?; /// stream.write_int(123u16, 15)?;
@ -31,17 +30,14 @@ const USIZE_BITS: usize = USIZE_SIZE * 8;
/// ``` /// ```
/// ///
/// [`BitBuffer`]: struct.BitBuffer.html /// [`BitBuffer`]: struct.BitBuffer.html
#[derive(Clone)] pub struct BitWriteStream<'a, E>
pub struct BitWriteStream<E>
where where
E: Endianness, E: Endianness,
{ {
bytes: Vec<u8>, buffer: WriteBuffer<'a, E>,
bit_len: usize,
endianness: PhantomData<E>,
} }
impl<E> BitWriteStream<E> impl<'a, E> BitWriteStream<'a, E>
where where
E: Endianness, E: Endianness,
{ {
@ -52,29 +48,28 @@ where
/// ``` /// ```
/// use bitbuffer::{BitWriteStream, LittleEndian}; /// use bitbuffer::{BitWriteStream, LittleEndian};
/// ///
/// let mut stream = BitWriteStream::new(LittleEndian); /// let mut data = Vec::new();
/// let mut stream = BitWriteStream::new(&mut data, LittleEndian);
/// ``` /// ```
pub fn new(_endianness: E) -> Self { pub fn new(data: &'a mut Vec<u8>, endianness: E) -> Self {
BitWriteStream { BitWriteStream {
bytes: Vec::new(), buffer: WriteBuffer::new(data, endianness),
bit_len: 0,
endianness: PhantomData,
} }
} }
} }
impl<E> BitWriteStream<E> impl<'a, E> BitWriteStream<'a, E>
where where
E: Endianness, E: Endianness,
{ {
/// The number of written bits in the buffer /// The number of written bits in the buffer
pub fn bit_len(&self) -> usize { pub fn bit_len(&self) -> usize {
self.bit_len self.buffer.bit_len()
} }
/// The number of written bytes in the buffer /// The number of written bytes in the buffer
pub fn byte_len(&self) -> usize { pub fn byte_len(&self) -> usize {
self.bytes.len() (self.buffer.bit_len() + 7) / 8
} }
fn push_non_fit_bits<I>(&mut self, bits: I, count: usize) fn push_non_fit_bits<I>(&mut self, bits: I, count: usize)
@ -82,48 +77,12 @@ where
I: ExactSizeIterator, I: ExactSizeIterator,
I: DoubleEndedIterator<Item = u8>, I: DoubleEndedIterator<Item = u8>,
{ {
let full_bytes = min(bits.len() - 1, count / 8); self.buffer.push_non_fit_bits(bits, count)
let counts = repeat(8)
.take(full_bytes)
.chain(once(count - full_bytes * 8));
if E::is_le() {
bits.zip(counts)
.for_each(|(chunk, count)| self.push_bits(chunk as usize, count))
} else {
bits.take(count / 8 + 1)
.rev()
.zip(counts)
.for_each(|(chunk, count)| self.push_bits(chunk as usize, count))
}
} }
/// Push up to an usize worth of bits /// Push up to an usize worth of bits
fn push_bits(&mut self, bits: usize, count: usize) { fn push_bits(&mut self, bits: usize, count: usize) {
debug_assert!(count < USIZE_BITS - 8); self.buffer.push_bits(bits, count)
// ensure there are no stray bits
let bits = bits & (usize::MAX >> (USIZE_BITS - count));
let bit_offset = self.bit_len & 7;
let last_written_byte = if bit_offset > 0 {
self.bytes.pop().unwrap_or(0)
} else {
0
};
let merged_byte_count = (count + bit_offset + 7) / 8;
if E::is_le() {
let merged = last_written_byte as usize | bits << bit_offset;
self.bytes
.extend_from_slice(&merged.to_le_bytes()[0..merged_byte_count]);
} else {
let merged = ((last_written_byte as usize) << (USIZE_BITS - 8))
| (bits << (USIZE_BITS - bit_offset - count));
self.bytes
.extend_from_slice(&merged.to_be_bytes()[0..merged_byte_count]);
}
self.bit_len += count;
} }
/// Write a boolean into the buffer /// Write a boolean into the buffer
@ -136,7 +95,8 @@ where
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// # use bitbuffer::{BitWriteStream, LittleEndian}; /// # use bitbuffer::{BitWriteStream, LittleEndian};
/// ///
/// let mut stream = BitWriteStream::new(LittleEndian); /// let mut data = Vec::new();
/// let mut stream = BitWriteStream::new(&mut data, LittleEndian);
/// stream.write_bool(true)?; /// stream.write_bool(true)?;
/// # /// #
/// # Ok(()) /// # Ok(())
@ -158,7 +118,8 @@ where
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// # use bitbuffer::{BitWriteStream, LittleEndian}; /// # use bitbuffer::{BitWriteStream, LittleEndian};
/// ///
/// let mut stream = BitWriteStream::new(LittleEndian); /// let mut data = Vec::new();
/// let mut stream = BitWriteStream::new(&mut data, LittleEndian);
/// stream.write_int(123u16, 15)?; /// stream.write_int(123u16, 15)?;
/// # /// #
/// # Ok(()) /// # Ok(())
@ -197,7 +158,8 @@ where
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// # use bitbuffer::{BitWriteStream, LittleEndian}; /// # use bitbuffer::{BitWriteStream, LittleEndian};
/// ///
/// let mut stream = BitWriteStream::new(LittleEndian); /// let mut data = Vec::new();
/// let mut stream = BitWriteStream::new(&mut data, LittleEndian);
/// stream.write_float(123.15f32)?; /// stream.write_float(123.15f32)?;
/// # /// #
/// # Ok(()) /// # Ok(())
@ -231,7 +193,8 @@ where
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// # use bitbuffer::{BitWriteStream, LittleEndian}; /// # use bitbuffer::{BitWriteStream, LittleEndian};
/// ///
/// let mut stream = BitWriteStream::new(LittleEndian); /// let mut data = Vec::new();
/// let mut stream = BitWriteStream::new(&mut data, LittleEndian);
/// stream.write_bytes(&[0, 1, 2 ,3])?; /// stream.write_bytes(&[0, 1, 2 ,3])?;
/// # /// #
/// # Ok(()) /// # Ok(())
@ -250,7 +213,7 @@ where
#[inline] #[inline]
pub fn write_bits(&mut self, bits: &BitReadStream<E>) -> Result<()> { pub fn write_bits(&mut self, bits: &BitReadStream<E>) -> Result<()> {
let mut bits = bits.clone(); let mut bits = bits.clone();
let bit_offset = self.bit_len % 8; let bit_offset = self.bit_len() % 8;
if bit_offset > 0 { if bit_offset > 0 {
let start = bits.read_int::<u8>(8 - bit_offset)?; let start = bits.read_int::<u8>(8 - bit_offset)?;
self.push_bits(start as usize, 8 - bit_offset); self.push_bits(start as usize, 8 - bit_offset);
@ -269,15 +232,6 @@ where
Ok(()) Ok(())
} }
/// Add a number of padding bytes
fn zero_pad(&mut self, count: usize) {
// since partly written bytes are already 0 padded, we don't need to go trough all the hoop
// of merging the padding bits into the partly written bytes
// (also because x | 0 == x)
self.bytes.resize(self.bytes.len() + count, 0);
self.bit_len += count * 8;
}
/// Write a string into the buffer /// Write a string into the buffer
/// ///
/// # Examples /// # Examples
@ -288,7 +242,8 @@ where
/// # fn main() -> Result<()> { /// # fn main() -> Result<()> {
/// # use bitbuffer::{BitWriteStream, LittleEndian}; /// # use bitbuffer::{BitWriteStream, LittleEndian};
/// ///
/// let mut stream = BitWriteStream::new(LittleEndian); /// let mut data = Vec::new();
/// let mut stream = BitWriteStream::new(&mut data, LittleEndian);
/// stream.write_string("zero terminated string", None)?; /// stream.write_string("zero terminated string", None)?;
/// stream.write_string("fixed size string, zero padded", Some(64))?; /// stream.write_string("fixed size string, zero padded", Some(64))?;
/// # /// #
@ -305,21 +260,18 @@ where
}); });
} }
self.write_bytes(&string.as_bytes())?; self.write_bytes(&string.as_bytes())?;
self.zero_pad(length - string.len()); for _ in 0..(length - string.len()) {
self.push_bits(0, 8)
}
} }
None => { None => {
self.write_bytes(&string.as_bytes())?; self.write_bytes(&string.as_bytes())?;
self.zero_pad(1); self.push_bits(0, 8)
} }
} }
Ok(()) Ok(())
} }
/// Convert the write buffer into the written bytes
pub fn finish(self) -> Vec<u8> {
self.bytes
}
/// Write the type to stream /// Write the type to stream
#[inline] #[inline]
pub fn write<T: BitWrite<E>>(&mut self, value: &T) -> Result<()> { pub fn write<T: BitWrite<E>>(&mut self, value: &T) -> Result<()> {
@ -331,4 +283,15 @@ where
pub fn write_sized<T: BitWriteSized<E>>(&mut self, value: &T, length: usize) -> Result<()> { pub fn write_sized<T: BitWriteSized<E>>(&mut self, value: &T, length: usize) -> Result<()> {
value.write_sized(self, length) value.write_sized(self, length)
} }
/// Reserve some bits to be written later by splitting of two parts
///
/// This allows skipping a few bits to write later
pub fn reserve(&mut self, count: usize) -> (BitWriteStream<E>, BitWriteStream<E>) {
let (head, tail) = self.buffer.reserve(count);
(
BitWriteStream { buffer: head },
BitWriteStream { buffer: tail },
)
}
} }

View file

@ -14,19 +14,19 @@ fn roundtrip<
val: T, val: T,
) { ) {
{ {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write(&val).unwrap(); stream.write(&val).unwrap();
let size = stream.bit_len(); let size = stream.bit_len();
let data = stream.finish();
let mut read = BitReadStream::new(BitReadBuffer::new_owned(data, LittleEndian)); let mut read = BitReadStream::new(BitReadBuffer::new_owned(data, LittleEndian));
assert_eq!(val, read.read().unwrap()); assert_eq!(val, read.read().unwrap());
assert_eq!(size, read.pos()); assert_eq!(size, read.pos());
} }
{ {
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream.write(&val).unwrap(); stream.write(&val).unwrap();
let size = stream.bit_len(); let size = stream.bit_len();
let data = stream.finish();
let mut read = BitReadStream::new(BitReadBuffer::new_owned(data, BigEndian)); let mut read = BitReadStream::new(BitReadBuffer::new_owned(data, BigEndian));
assert_eq!(val, read.read().unwrap()); assert_eq!(val, read.read().unwrap());
assert_eq!(size, read.pos()); assert_eq!(size, read.pos());

View file

@ -2,14 +2,14 @@ use bitbuffer::{BigEndian, BitReadBuffer, BitReadStream, BitWriteStream, LittleE
#[test] #[test]
fn test_write_bool_le() { fn test_write_bool_le() {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_bool(false).unwrap(); stream.write_bool(false).unwrap();
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian));
assert_eq!(true, read.read_bool().unwrap()); assert_eq!(true, read.read_bool().unwrap());
@ -23,14 +23,14 @@ fn test_write_bool_le() {
#[test] #[test]
fn test_write_bool_be() { fn test_write_bool_be() {
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_bool(false).unwrap(); stream.write_bool(false).unwrap();
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, BigEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, BigEndian));
assert_eq!(true, read.read_bool().unwrap()); assert_eq!(true, read.read_bool().unwrap());
@ -44,13 +44,13 @@ fn test_write_bool_be() {
#[test] #[test]
fn test_write_bool_number_le() { fn test_write_bool_number_le() {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_int(3253u16, 16).unwrap(); stream.write_int(3253u16, 16).unwrap();
stream.write_int(13253u64, 64).unwrap(); stream.write_int(13253u64, 64).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian));
assert_eq!(true, read.read_bool().unwrap()); assert_eq!(true, read.read_bool().unwrap());
@ -63,13 +63,13 @@ fn test_write_bool_number_le() {
#[test] #[test]
fn test_write_bool_number_be() { fn test_write_bool_number_be() {
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_int(3253u16, 16).unwrap(); stream.write_int(3253u16, 16).unwrap();
stream.write_int(13253u64, 64).unwrap(); stream.write_int(13253u64, 64).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, BigEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, BigEndian));
assert_eq!(1u8, read.read_int(1).unwrap()); assert_eq!(1u8, read.read_int(1).unwrap());
@ -82,12 +82,12 @@ fn test_write_bool_number_be() {
#[test] #[test]
fn test_write_float_le() { fn test_write_float_le() {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_float(3253.12f32).unwrap(); stream.write_float(3253.12f32).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian));
assert_eq!(true, read.read_bool().unwrap()); assert_eq!(true, read.read_bool().unwrap());
@ -99,12 +99,12 @@ fn test_write_float_le() {
#[test] #[test]
fn test_write_float_be() { fn test_write_float_be() {
let mut stream = BitWriteStream::new(BigEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, BigEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_float(3253.12f32).unwrap(); stream.write_float(3253.12f32).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, BigEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, BigEndian));
assert_eq!(1u8, read.read_int(1).unwrap()); assert_eq!(1u8, read.read_int(1).unwrap());
@ -116,13 +116,13 @@ fn test_write_float_be() {
#[test] #[test]
fn test_write_string_le() { fn test_write_string_le() {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write_string("null terminated", None).unwrap(); stream.write_string("null terminated", None).unwrap();
stream.write_string("fixed length1", Some(16)).unwrap(); stream.write_string("fixed length1", Some(16)).unwrap();
stream.write_string("fixed length2", Some(16)).unwrap(); stream.write_string("fixed length2", Some(16)).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian));
assert_eq!("null terminated", read.read_string(None).unwrap()); assert_eq!("null terminated", read.read_string(None).unwrap());
@ -132,14 +132,14 @@ fn test_write_string_le() {
#[test] #[test]
fn test_write_string_le_unaligned() { fn test_write_string_le_unaligned() {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_string("null terminated", None).unwrap(); stream.write_string("null terminated", None).unwrap();
stream.write_string("fixed length1", Some(16)).unwrap(); stream.write_string("fixed length1", Some(16)).unwrap();
stream.write_string("fixed length2", Some(16)).unwrap(); stream.write_string("fixed length2", Some(16)).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian));
assert_eq!(true, read.read_bool().unwrap()); assert_eq!(true, read.read_bool().unwrap());
@ -153,13 +153,13 @@ fn test_write_string_le_unaligned() {
#[test] #[test]
fn test_write_signed() { fn test_write_signed() {
let mut stream = BitWriteStream::new(LittleEndian); let mut data = Vec::new();
let mut stream = BitWriteStream::new(&mut data, LittleEndian);
stream.write_bool(true).unwrap(); stream.write_bool(true).unwrap();
stream.write_int(-17i32, 32).unwrap(); stream.write_int(-17i32, 32).unwrap();
stream.write_int(-9i32, 8).unwrap(); stream.write_int(-9i32, 8).unwrap();
let data = stream.finish();
let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian)); let mut read = BitReadStream::from(BitReadBuffer::new(&data, LittleEndian));
assert_eq!(true, read.read_bool().unwrap()); assert_eq!(true, read.read_bool().unwrap());