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:
parent
51faeababf
commit
4872cd62c4
4 changed files with 93 additions and 23 deletions
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue