mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
make write stream borrow the data to allow splitting/reserving
This commit is contained in:
parent
3bc1ece2ab
commit
9bced05a9d
6 changed files with 480 additions and 126 deletions
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
381
src/writebuffer.rs
Normal 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)
|
||||||
|
}
|
||||||
|
|
@ -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 },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue