1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 16:44:06 +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;
/// Input is big endian
fn is_be() -> bool;
/// Get an instance of the endianness
fn endianness() -> Self;
}
/// Marks the buffer or stream as big endian
@ -24,7 +26,7 @@ pub struct BigEndian;
pub struct LittleEndian;
macro_rules! impl_endianness {
($type:ty, $le:expr) => {
($type:ty, $le:expr, $instance:expr) => {
impl Endianness for $type {
#[inline(always)]
fn is_le() -> bool {
@ -35,12 +37,16 @@ macro_rules! impl_endianness {
fn is_be() -> bool {
!$le
}
fn endianness() -> Self {
$instance
}
}
};
}
impl_endianness!(BigEndian, false);
impl_endianness!(LittleEndian, true);
impl_endianness!(BigEndian, false, BigEndian);
impl_endianness!(LittleEndian, true, LittleEndian);
mod private {
pub trait Sealed {}

View file

@ -18,7 +18,7 @@ const USIZE_SIZE: usize = size_of::<usize>();
const USIZE_BIT_SIZE: usize = USIZE_SIZE * 8;
// Cow<[u8]> but with cheap clones using Rc
enum Data<'a> {
pub(crate) enum Data<'a> {
Borrowed(&'a [u8]),
Owned(Rc<[u8]>),
}
@ -34,6 +34,14 @@ impl<'a> Data<'a> {
pub fn len(&self) -> usize {
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> {
@ -92,7 +100,7 @@ pub struct BitReadBuffer<'a, E>
where
E: Endianness,
{
bytes: Data<'a>,
pub(crate) bytes: Data<'a>,
bit_len: usize,
endianness: PhantomData<E>,
slice: &'a [u8],
@ -125,6 +133,27 @@ where
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>
@ -190,7 +219,7 @@ where
/// The available number of bytes in the buffer
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] {
@ -710,28 +739,13 @@ where
impl<'a, E: Endianness> From<&'a [u8]> for BitReadBuffer<'a, E> {
fn from(bytes: &'a [u8]) -> Self {
let byte_len = bytes.len();
BitReadBuffer {
bytes: Data::Borrowed(bytes),
bit_len: byte_len * 8,
endianness: PhantomData,
slice: bytes,
}
BitReadBuffer::new(bytes, E::endianness())
}
}
impl<'a, E: Endianness> From<Vec<u8>> for BitReadBuffer<'a, E> {
fn from(bytes: Vec<u8>) -> Self {
let byte_len = bytes.len();
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,
}
BitReadBuffer::new_owned(bytes, E::endianness())
}
}

View file

@ -5,6 +5,7 @@ use num_traits::{Float, PrimInt};
use crate::endianness::Endianness;
use crate::num_traits::{IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::readbuffer::Data;
use crate::BitReadBuffer;
use crate::{BitError, BitRead, BitReadSized, Result};
use std::borrow::Cow;
@ -660,6 +661,37 @@ where
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> {