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;
|
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 {}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue