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

add to_owned

This commit is contained in:
Robin Appelman 2020-12-06 21:02:42 +01:00
commit 4872cd62c4
4 changed files with 93 additions and 23 deletions

View file

@ -13,6 +13,8 @@ pub trait Endianness: private::Sealed {
fn is_le() -> bool; fn is_le() -> bool;
/// Input is big endian /// Input is big endian
fn is_be() -> bool; fn is_be() -> bool;
/// Get an instance of the endianness
fn endianness() -> Self;
} }
/// Marks the buffer or stream as big endian /// Marks the buffer or stream as big endian
@ -24,7 +26,7 @@ pub struct BigEndian;
pub struct LittleEndian; pub struct LittleEndian;
macro_rules! impl_endianness { macro_rules! impl_endianness {
($type:ty, $le:expr) => { ($type:ty, $le:expr, $instance:expr) => {
impl Endianness for $type { impl Endianness for $type {
#[inline(always)] #[inline(always)]
fn is_le() -> bool { fn is_le() -> bool {
@ -35,12 +37,16 @@ macro_rules! impl_endianness {
fn is_be() -> bool { fn is_be() -> bool {
!$le !$le
} }
fn endianness() -> Self {
$instance
}
} }
}; };
} }
impl_endianness!(BigEndian, false); impl_endianness!(BigEndian, false, BigEndian);
impl_endianness!(LittleEndian, true); impl_endianness!(LittleEndian, true, LittleEndian);
mod private { mod private {
pub trait Sealed {} pub trait Sealed {}

View file

@ -18,7 +18,7 @@ const USIZE_SIZE: usize = size_of::<usize>();
const USIZE_BIT_SIZE: usize = USIZE_SIZE * 8; const USIZE_BIT_SIZE: usize = USIZE_SIZE * 8;
// Cow<[u8]> but with cheap clones using Rc // Cow<[u8]> but with cheap clones using Rc
enum Data<'a> { pub(crate) enum Data<'a> {
Borrowed(&'a [u8]), Borrowed(&'a [u8]),
Owned(Rc<[u8]>), Owned(Rc<[u8]>),
} }
@ -34,6 +34,14 @@ impl<'a> Data<'a> {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.as_slice().len() self.as_slice().len()
} }
pub fn to_owned(&self) -> Data<'static> {
let bytes = match self {
Data::Borrowed(bytes) => Rc::from(bytes.to_vec()),
Data::Owned(bytes) => Rc::clone(bytes),
};
Data::Owned(bytes.into())
}
} }
impl<'a> Index<Range<usize>> for Data<'a> { impl<'a> Index<Range<usize>> for Data<'a> {
@ -92,7 +100,7 @@ pub struct BitReadBuffer<'a, E>
where where
E: Endianness, E: Endianness,
{ {
bytes: Data<'a>, pub(crate) bytes: Data<'a>,
bit_len: usize, bit_len: usize,
endianness: PhantomData<E>, endianness: PhantomData<E>,
slice: &'a [u8], slice: &'a [u8],
@ -125,6 +133,27 @@ where
slice: bytes, slice: bytes,
} }
} }
/// Create a static version of this buffer
///
/// If the current buffer is borrowed, this will copy the data
pub fn to_owned(&self) -> BitReadBuffer<'static, E> {
let bytes = self.bytes.to_owned();
let byte_len = bytes.len();
// this is safe because
// - the slice can only be access trough this struct
// - this struct keeps the vec the slice comes from alive
// - this struct doesn't allow mutation
let slice = unsafe { std::slice::from_raw_parts(bytes.as_slice().as_ptr(), bytes.len()) };
BitReadBuffer {
bytes,
bit_len: byte_len * 8,
endianness: PhantomData,
slice,
}
}
} }
impl<E> BitReadBuffer<'static, E> impl<E> BitReadBuffer<'static, E>
@ -190,7 +219,7 @@ where
/// The available number of bytes in the buffer /// The available number of bytes in the buffer
pub fn byte_len(&self) -> usize { pub fn byte_len(&self) -> usize {
self.bytes.len() self.slice.len()
} }
unsafe fn read_usize_bytes(&self, byte_index: usize, end: bool) -> [u8; USIZE_SIZE] { unsafe fn read_usize_bytes(&self, byte_index: usize, end: bool) -> [u8; USIZE_SIZE] {
@ -710,28 +739,13 @@ where
impl<'a, E: Endianness> From<&'a [u8]> for BitReadBuffer<'a, E> { impl<'a, E: Endianness> From<&'a [u8]> for BitReadBuffer<'a, E> {
fn from(bytes: &'a [u8]) -> Self { fn from(bytes: &'a [u8]) -> Self {
let byte_len = bytes.len(); BitReadBuffer::new(bytes, E::endianness())
BitReadBuffer {
bytes: Data::Borrowed(bytes),
bit_len: byte_len * 8,
endianness: PhantomData,
slice: bytes,
}
} }
} }
impl<'a, E: Endianness> From<Vec<u8>> for BitReadBuffer<'a, E> { impl<'a, E: Endianness> From<Vec<u8>> for BitReadBuffer<'a, E> {
fn from(bytes: Vec<u8>) -> Self { fn from(bytes: Vec<u8>) -> Self {
let byte_len = bytes.len(); BitReadBuffer::new_owned(bytes, E::endianness())
let bytes = Data::Owned(Rc::from(bytes));
let slice = unsafe { std::slice::from_raw_parts(bytes.as_slice().as_ptr(), bytes.len()) };
BitReadBuffer {
bytes,
bit_len: byte_len * 8,
endianness: PhantomData,
slice,
}
} }
} }

View file

@ -5,6 +5,7 @@ use num_traits::{Float, PrimInt};
use crate::endianness::Endianness; use crate::endianness::Endianness;
use crate::num_traits::{IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt}; use crate::num_traits::{IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::readbuffer::Data;
use crate::BitReadBuffer; use crate::BitReadBuffer;
use crate::{BitError, BitRead, BitReadSized, Result}; use crate::{BitError, BitRead, BitReadSized, Result};
use std::borrow::Cow; use std::borrow::Cow;
@ -660,6 +661,37 @@ where
Ok(false) Ok(false)
} }
} }
/// Create an owned copy of this stream
pub fn to_owned(&self) -> BitReadStream<'static, E> {
match self.buffer.bytes {
Data::Owned(_) => BitReadStream {
// already owned, so buffer.to_owned is a cheap rc clone
buffer: self.buffer.to_owned(),
start_pos: self.pos,
pos: self.pos,
},
Data::Borrowed(bytes) => {
// instead of calling buffer.to_owned blindly, we only copy the bytes that this stream covers
let byte_pos = self.start_pos / 8;
let bit_offset = self.start_pos & 7;
let end = self.buffer.bit_len() / 8 + 1;
let end = min(end, self.buffer.byte_len());
let sub_bytes = bytes[byte_pos..end].to_vec();
let buffer = BitReadBuffer::from(sub_bytes)
.get_sub_buffer(self.buffer.bit_len() - self.start_pos + bit_offset)
.unwrap();
BitReadStream {
buffer,
start_pos: bit_offset,
pos: bit_offset + (self.pos - self.start_pos),
}
}
}
}
} }
impl<'a, E: Endianness> Clone for BitReadStream<'a, E> { impl<'a, E: Endianness> Clone for BitReadStream<'a, E> {

View file

@ -455,3 +455,21 @@ fn read_read_signed() {
let buffer = BitReadBuffer::new(&byte_vec, LittleEndian); let buffer = BitReadBuffer::new(&byte_vec, LittleEndian);
assert_eq!(buffer.read_int::<i32>(0, 32).unwrap(), -10); assert_eq!(buffer.read_int::<i32>(0, 32).unwrap(), -10);
} }
#[test]
fn test_to_owned_stream() {
let bytes = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
let buffer = BitReadBuffer::new(&bytes, LittleEndian);
let mut stream = BitReadStream::new(buffer);
let mut stream = stream.read_bits(15 * 7).unwrap();
stream.skip_bits(25).unwrap();
let mut owned = stream.to_owned();
assert_eq!(stream.read::<u8>().unwrap(), owned.read::<u8>().unwrap());
assert_eq!(stream.read::<u16>().unwrap(), owned.read::<u16>().unwrap());
assert_eq!(stream.read::<u8>().unwrap(), owned.read::<u8>().unwrap());
assert_eq!(stream.bit_len(), owned.bit_len());
assert_eq!(stream.bits_left(), owned.bits_left());
}