mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
drop read_*_into for now as it doesn't seem to help much for the complexity
This commit is contained in:
parent
c03bf99c3b
commit
b87a6fb209
6 changed files with 54 additions and 348 deletions
42
Cargo.lock
generated
42
Cargo.lock
generated
|
|
@ -22,6 +22,7 @@ name = "bitbuffer"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitbuffer_derive",
|
"bitbuffer_derive",
|
||||||
|
"compact_str",
|
||||||
"iai-callgrind",
|
"iai-callgrind",
|
||||||
"maplit",
|
"maplit",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
|
@ -43,6 +44,35 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "castaway"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
|
||||||
|
dependencies = [
|
||||||
|
"rustversion",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "compact_str"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
|
||||||
|
dependencies = [
|
||||||
|
"castaway",
|
||||||
|
"cfg-if",
|
||||||
|
"itoa",
|
||||||
|
"rustversion",
|
||||||
|
"ryu",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
|
@ -194,6 +224,12 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.19"
|
version = "1.0.19"
|
||||||
|
|
@ -267,6 +303,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "structmeta"
|
name = "structmeta"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ thiserror = "2.0.11"
|
||||||
bitbuffer_derive = { version = "0.11.0", path = "bitbuffer_derive" }
|
bitbuffer_derive = { version = "0.11.0", path = "bitbuffer_derive" }
|
||||||
serde = { version = "1.0.218", features = ["derive"], optional = true }
|
serde = { version = "1.0.218", features = ["derive"], optional = true }
|
||||||
schemars = { version = "0.8.21", optional = true }
|
schemars = { version = "0.8.21", optional = true }
|
||||||
|
compact_str = "0.9.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
|
|
|
||||||
|
|
@ -121,26 +121,6 @@ fn perf_string<E: Endianness>((offset, buffer): (usize, BitReadBuffer<E>)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[library_benchmark(setup = build_string_buffer)]
|
|
||||||
#[bench::le_alligned(0, LittleEndian)]
|
|
||||||
#[bench::be_alligned(0, BigEndian)]
|
|
||||||
#[bench::le_unalligned(3, LittleEndian)]
|
|
||||||
#[bench::be_unalligned(3, BigEndian)]
|
|
||||||
fn perf_string_into<E: Endianness>((offset, buffer): (usize, BitReadBuffer<E>)) {
|
|
||||||
let mut pos = offset;
|
|
||||||
let len = buffer.bit_len();
|
|
||||||
let mut buff = String::new();
|
|
||||||
loop {
|
|
||||||
if pos + (128 * 8) > len {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let result = buffer.read_string_into(pos, None, &mut buff).unwrap();
|
|
||||||
let result = result.as_ref(&buff);
|
|
||||||
pos += (result.len() + 1) * 8;
|
|
||||||
black_box(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[library_benchmark(setup = build_string_buffer)]
|
#[library_benchmark(setup = build_string_buffer)]
|
||||||
#[bench::le_alligned(0, LittleEndian)]
|
#[bench::le_alligned(0, LittleEndian)]
|
||||||
#[bench::be_alligned(0, BigEndian)]
|
#[bench::be_alligned(0, BigEndian)]
|
||||||
|
|
@ -159,26 +139,6 @@ fn perf_bytes<E: Endianness>((offset, buffer): (usize, BitReadBuffer<E>)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[library_benchmark(setup = build_string_buffer)]
|
|
||||||
#[bench::le_alligned(0, LittleEndian)]
|
|
||||||
#[bench::be_alligned(0, BigEndian)]
|
|
||||||
#[bench::le_unalligned(3, LittleEndian)]
|
|
||||||
#[bench::be_unalligned(3, BigEndian)]
|
|
||||||
fn perf_bytes_into<E: Endianness>((offset, buffer): (usize, BitReadBuffer<E>)) {
|
|
||||||
let mut pos = offset;
|
|
||||||
let len = buffer.bit_len();
|
|
||||||
let mut buff = Vec::new();
|
|
||||||
loop {
|
|
||||||
if pos + (128 * 8) > len {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let result = buffer.read_bytes_into(pos, 128, &mut buff).unwrap();
|
|
||||||
let result = result.as_ref(&buff);
|
|
||||||
pos += (result.len() + 1) * 8;
|
|
||||||
black_box(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(BitRead)]
|
#[derive(BitRead)]
|
||||||
struct BasicStruct {
|
struct BasicStruct {
|
||||||
|
|
@ -230,14 +190,12 @@ library_benchmark_group!(
|
||||||
|
|
||||||
library_benchmark_group!(
|
library_benchmark_group!(
|
||||||
name = bench_read_string;
|
name = bench_read_string;
|
||||||
compare_by_id = true;
|
benchmarks = perf_string
|
||||||
benchmarks = perf_string, perf_string_into
|
|
||||||
);
|
);
|
||||||
|
|
||||||
library_benchmark_group!(
|
library_benchmark_group!(
|
||||||
name = bench_read_bytes;
|
name = bench_read_bytes;
|
||||||
compare_by_id = true;
|
benchmarks = perf_bytes
|
||||||
benchmarks = perf_bytes, perf_bytes_into
|
|
||||||
);
|
);
|
||||||
|
|
||||||
library_benchmark_group!(
|
library_benchmark_group!(
|
||||||
|
|
|
||||||
47
src/lib.rs
47
src/lib.rs
|
|
@ -75,7 +75,6 @@
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub use bitbuffer_derive::{BitRead, BitReadSized, BitWrite, BitWriteSized};
|
pub use bitbuffer_derive::{BitRead, BitReadSized, BitWrite, BitWriteSized};
|
||||||
|
|
@ -191,49 +190,3 @@ pub fn bit_size_of<'a, T: BitRead<'a, LittleEndian>>() -> Option<usize> {
|
||||||
pub fn bit_size_of_sized<'a, T: BitReadSized<'a, LittleEndian>>(size: usize) -> Option<usize> {
|
pub fn bit_size_of_sized<'a, T: BitReadSized<'a, LittleEndian>>(size: usize) -> Option<usize> {
|
||||||
T::bit_size_sized(size)
|
T::bit_size_sized(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A result that is either borrowed from the source buffer, or written into the provided output buffer
|
|
||||||
///
|
|
||||||
/// This is similar to `Cow` but allows reusing the owned allocation
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum MaybeBorrowed<'a, B>
|
|
||||||
where
|
|
||||||
B: 'a + ToOwned + ?Sized,
|
|
||||||
{
|
|
||||||
/// Result borrowed from the source buffer
|
|
||||||
Borrowed(&'a B),
|
|
||||||
/// Marks that the result has been written into the provided output buffer,
|
|
||||||
Owned,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, B: 'a + ToOwned + ?Sized> MaybeBorrowed<'a, B> {
|
|
||||||
/// Create a `Cow<'a, B>` from the `MaybeBorrowed<'a, B>` and the buffer containing the owned data.
|
|
||||||
pub fn into_cow(self, owned_buffer: B::Owned) -> Cow<'a, B> {
|
|
||||||
match self {
|
|
||||||
MaybeBorrowed::Borrowed(b) => Cow::Borrowed(b),
|
|
||||||
MaybeBorrowed::Owned => Cow::Owned(owned_buffer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an owned copy of the data, either by copying the borrowed data or using the owned data.
|
|
||||||
pub fn to_owned(&self, owned_buffer: B::Owned) -> B::Owned {
|
|
||||||
match *self {
|
|
||||||
MaybeBorrowed::Borrowed(b) => b.to_owned(),
|
|
||||||
MaybeBorrowed::Owned => owned_buffer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, B> MaybeBorrowed<'a, B>
|
|
||||||
where
|
|
||||||
B: 'a + ToOwned + ?Sized,
|
|
||||||
B::Owned: AsRef<B>,
|
|
||||||
{
|
|
||||||
/// Get a reference from either the `MaybeBorrowed<'a, B>` or the buffer containing the owned data.
|
|
||||||
pub fn as_ref<'o>(&'o self, owned_buffer: &'o B::Owned) -> &'o B {
|
|
||||||
match self {
|
|
||||||
MaybeBorrowed::Borrowed(b) => b,
|
|
||||||
MaybeBorrowed::Owned => owned_buffer.as_ref(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ use std::cmp::min;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::{size_of, take};
|
use std::mem::size_of;
|
||||||
use std::ops::{BitOrAssign, BitXor, Index, Range, RangeFrom};
|
use std::ops::{BitOrAssign, BitXor, Index, Range, RangeFrom};
|
||||||
|
|
||||||
use num_traits::{Float, PrimInt, WrappingSub};
|
use num_traits::{Float, PrimInt, WrappingSub};
|
||||||
|
|
||||||
use crate::endianness::Endianness;
|
use crate::endianness::Endianness;
|
||||||
use crate::num_traits::{IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
|
use crate::num_traits::{IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
|
||||||
use crate::{BitError, MaybeBorrowed, Result};
|
use crate::{BitError, Result};
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -512,54 +512,6 @@ where
|
||||||
Ok(unsafe { self.read_bytes_unchecked(position, byte_count) })
|
Ok(unsafe { self.read_bytes_unchecked(position, byte_count) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a series of bytes from the buffer, using an existing buffer
|
|
||||||
///
|
|
||||||
/// If the `position` is a multiple of 8, the output will be borrowed, otherwise it will be written to the provided output buffer
|
|
||||||
///
|
|
||||||
/// See `[MaybeBorrowed]` for more information for dealing with the result.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// - [`ReadError::NotEnoughData`]: not enough bits available in the buffer
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bitbuffer::{BitReadBuffer, LittleEndian, Result};
|
|
||||||
/// #
|
|
||||||
/// # fn main() -> Result<()> {
|
|
||||||
/// # let bytes = vec![
|
|
||||||
/// # 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
|
||||||
/// # 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
|
||||||
/// # ];
|
|
||||||
/// # let buffer = BitReadBuffer::new(&bytes, LittleEndian);
|
|
||||||
/// let mut output = Vec::new();
|
|
||||||
/// let result = buffer.read_bytes_into(5, 3, &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), &[0b0_1010_101, 0b0_1100_011, 0b1_1001_101]);
|
|
||||||
/// output.clear();
|
|
||||||
/// let result = buffer.read_bytes_into(0, 8, &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), &[
|
|
||||||
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
|
||||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
|
||||||
/// ]);
|
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`ReadError::NotEnoughData`]: enum.ReadError.html#variant.NotEnoughData
|
|
||||||
#[inline]
|
|
||||||
pub fn read_bytes_into(
|
|
||||||
&self,
|
|
||||||
position: usize,
|
|
||||||
byte_count: usize,
|
|
||||||
output: &mut Vec<u8>,
|
|
||||||
) -> Result<MaybeBorrowed<'a, [u8]>> {
|
|
||||||
self.bounds_check(position, byte_count * 8)?;
|
|
||||||
|
|
||||||
Ok(unsafe { self.read_bytes_unchecked_into(position, byte_count, output) })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn read_bytes_unchecked_owned(
|
unsafe fn read_bytes_unchecked_owned(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -567,6 +519,9 @@ where
|
||||||
byte_count: usize,
|
byte_count: usize,
|
||||||
output: &mut Vec<u8>,
|
output: &mut Vec<u8>,
|
||||||
) {
|
) {
|
||||||
|
output.clear();
|
||||||
|
output.reserve(byte_count);
|
||||||
|
|
||||||
let shift = position & 7;
|
let shift = position & 7;
|
||||||
let mut byte_left = byte_count;
|
let mut byte_left = byte_count;
|
||||||
let mut read_pos = position / 8;
|
let mut read_pos = position / 8;
|
||||||
|
|
@ -612,28 +567,6 @@ where
|
||||||
Cow::Owned(output)
|
Cow::Owned(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn read_bytes_unchecked_into(
|
|
||||||
&self,
|
|
||||||
position: usize,
|
|
||||||
byte_count: usize,
|
|
||||||
output: &mut Vec<u8>,
|
|
||||||
) -> MaybeBorrowed<'a, [u8]> {
|
|
||||||
let shift = position & 7;
|
|
||||||
|
|
||||||
if shift == 0 {
|
|
||||||
let byte_pos = position / 8;
|
|
||||||
return MaybeBorrowed::Borrowed(&self.slice[byte_pos..byte_pos + byte_count]);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.clear();
|
|
||||||
output.reserve(byte_count);
|
|
||||||
self.read_bytes_unchecked_owned(position, byte_count, output);
|
|
||||||
|
|
||||||
MaybeBorrowed::Owned
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a series of bytes from the buffer as string.
|
/// Read a series of bytes from the buffer as string.
|
||||||
///
|
///
|
||||||
/// You can either read a fixed number of bytes, or a dynamic length null-terminated string.
|
/// You can either read a fixed number of bytes, or a dynamic length null-terminated string.
|
||||||
|
|
@ -683,67 +616,6 @@ where
|
||||||
Ok(Cow::Owned(string))
|
Ok(Cow::Owned(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a series of bytes from the buffer as string.
|
|
||||||
///
|
|
||||||
/// You can either read a fixed number of bytes, or a dynamic length null-terminated string.
|
|
||||||
///
|
|
||||||
/// If the `position` is a multiple of 8, the output will be borrowed, otherwise it will be copied into the provided String.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// - [`ReadError::NotEnoughData`]: not enough bits available in the buffer
|
|
||||||
/// - [`ReadError::Utf8Error`]: the read bytes are not valid utf8
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bitbuffer::{BitReadBuffer, BitReadStream, LittleEndian, Result};
|
|
||||||
/// #
|
|
||||||
/// # fn main() -> Result<()> {
|
|
||||||
/// # let bytes = vec![
|
|
||||||
/// # 0x48, 0x65, 0x6c, 0x6c,
|
|
||||||
/// # 0x6f, 0x20, 0x77, 0x6f,
|
|
||||||
/// # 0x72, 0x6c, 0x64, 0,
|
|
||||||
/// # 0, 0, 0, 0
|
|
||||||
/// # ];
|
|
||||||
/// # let buffer = BitReadBuffer::new(&bytes, LittleEndian);
|
|
||||||
/// let mut output = String::new();
|
|
||||||
/// // Fixed length string
|
|
||||||
/// let result = buffer.read_string_into(0, Some(11), &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), "Hello world");
|
|
||||||
/// // fixed length with null padding
|
|
||||||
/// let result = buffer.read_string_into(0, Some(16), &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), "Hello world".to_owned());
|
|
||||||
/// // null terminated
|
|
||||||
/// let result = buffer.read_string_into(0, None, &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), "Hello world".to_owned());
|
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`ReadError::NotEnoughData`]: enum.ReadError.html#variant.NotEnoughData
|
|
||||||
/// [`ReadError::Utf8Error`]: enum.ReadError.html#variant.Utf8Error
|
|
||||||
#[inline]
|
|
||||||
pub fn read_string_into(
|
|
||||||
&self,
|
|
||||||
position: usize,
|
|
||||||
byte_len: Option<usize>,
|
|
||||||
output: &mut String,
|
|
||||||
) -> Result<MaybeBorrowed<'a, str>> {
|
|
||||||
let shift = position & 7;
|
|
||||||
if shift == 0 {
|
|
||||||
return Ok(MaybeBorrowed::Borrowed(
|
|
||||||
self.read_string_aligned(position, byte_len)?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let taken_output = take(output).into_bytes();
|
|
||||||
*output = self.read_string_unaligned(position, byte_len, taken_output)?;
|
|
||||||
|
|
||||||
Ok(MaybeBorrowed::Owned)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_string_unaligned(
|
fn read_string_unaligned(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ use num_traits::{Float, PrimInt, WrappingSub};
|
||||||
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::readbuffer::Data;
|
||||||
|
use crate::BitReadBuffer;
|
||||||
use crate::{BitError, BitRead, BitReadSized, Result};
|
use crate::{BitError, BitRead, BitReadSized, Result};
|
||||||
use crate::{BitReadBuffer, MaybeBorrowed};
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
|
|
@ -251,51 +251,6 @@ where
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a series of bytes from the stream
|
|
||||||
///
|
|
||||||
/// If the current read position is on a byte boundary, the output will be borrowed, otherwise it will be written to the provided output buffer
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// - [`ReadError::NotEnoughData`]: not enough bits available in the stream
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bitbuffer::{BitReadBuffer, BitReadStream, LittleEndian, Result};
|
|
||||||
/// #
|
|
||||||
/// # fn main() -> Result<()> {
|
|
||||||
/// # use std::borrow::Borrow;
|
|
||||||
/// let bytes = vec![
|
|
||||||
/// # 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
|
||||||
/// # 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
|
||||||
/// # ];
|
|
||||||
/// # let buffer = BitReadBuffer::new(&bytes, LittleEndian);
|
|
||||||
/// # let mut stream = BitReadStream::new(buffer);
|
|
||||||
/// let mut output = Vec::new();
|
|
||||||
/// let result = stream.read_bytes_into(3, &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), &[0b1011_0101, 0b0110_1010, 0b1010_1100]);
|
|
||||||
/// assert_eq!(stream.pos(), 24);
|
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`ReadError::NotEnoughData`]: enum.ReadError.html#variant.NotEnoughData
|
|
||||||
#[inline]
|
|
||||||
pub fn read_bytes_into(
|
|
||||||
&mut self,
|
|
||||||
byte_count: usize,
|
|
||||||
output: &mut Vec<u8>,
|
|
||||||
) -> Result<MaybeBorrowed<'a, [u8]>> {
|
|
||||||
let count = byte_count * 8;
|
|
||||||
let result = self.buffer.read_bytes_into(self.pos, byte_count, output);
|
|
||||||
if result.is_ok() {
|
|
||||||
self.pos += count;
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn read_bytes_unchecked(&mut self, byte_count: usize) -> Cow<'a, [u8]> {
|
pub unsafe fn read_bytes_unchecked(&mut self, byte_count: usize) -> Cow<'a, [u8]> {
|
||||||
|
|
@ -305,21 +260,6 @@ where
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn read_bytes_unchecked_into(
|
|
||||||
&mut self,
|
|
||||||
byte_count: usize,
|
|
||||||
output: &mut Vec<u8>,
|
|
||||||
) -> MaybeBorrowed<'a, [u8]> {
|
|
||||||
let count = byte_count * 8;
|
|
||||||
let result = self
|
|
||||||
.buffer
|
|
||||||
.read_bytes_unchecked_into(self.pos, byte_count, output);
|
|
||||||
self.pos += count;
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a series of bytes from the stream as utf8 string
|
/// Read a series of bytes from the stream as utf8 string
|
||||||
///
|
///
|
||||||
/// You can either read a fixed number of bytes, or a dynamic length null-terminated string
|
/// You can either read a fixed number of bytes, or a dynamic length null-terminated string
|
||||||
|
|
@ -366,76 +306,17 @@ where
|
||||||
/// [`ReadError::Utf8Error`]: enum.ReadError.html#variant.Utf8Error
|
/// [`ReadError::Utf8Error`]: enum.ReadError.html#variant.Utf8Error
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_string(&mut self, byte_len: Option<usize>) -> Result<Cow<'a, str>> {
|
pub fn read_string(&mut self, byte_len: Option<usize>) -> Result<Cow<'a, str>> {
|
||||||
let mut output = String::new();
|
|
||||||
let result = self.read_string_into(byte_len, &mut output)?;
|
|
||||||
Ok(result.into_cow(output))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a series of bytes from the stream as utf8 string
|
|
||||||
///
|
|
||||||
/// You can either read a fixed number of bytes, or a dynamic length null-terminated string
|
|
||||||
///
|
|
||||||
/// If the current read position is on a byte boundary, the output will be borrowed, otherwise it will be written to the provided output String
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// - [`ReadError::NotEnoughData`]: not enough bits available in the stream
|
|
||||||
/// - [`ReadError::Utf8Error`]: the read bytes are not valid utf8
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bitbuffer::{BitReadBuffer, BitReadStream, LittleEndian, Result};
|
|
||||||
/// #
|
|
||||||
/// # fn main() -> Result<()> {
|
|
||||||
/// # let bytes = vec![
|
|
||||||
/// # 0x48, 0x65, 0x6c, 0x6c,
|
|
||||||
/// # 0x6f, 0x20, 0x77, 0x6f,
|
|
||||||
/// # 0x72, 0x6c, 0x64, 0,
|
|
||||||
/// # 0, 0, 0, 0
|
|
||||||
/// # ];
|
|
||||||
/// # let buffer = BitReadBuffer::new(&bytes, LittleEndian);
|
|
||||||
/// # let mut stream = BitReadStream::new(buffer);
|
|
||||||
/// // Fixed length string
|
|
||||||
/// stream.set_pos(0);
|
|
||||||
/// let mut output = String::new();
|
|
||||||
/// let result = stream.read_string_into(Some(11), &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), "Hello world".to_owned());
|
|
||||||
/// assert_eq!(11 * 8, stream.pos());
|
|
||||||
/// // fixed length with null padding
|
|
||||||
/// stream.set_pos(0);
|
|
||||||
/// let result = stream.read_string_into(Some(16), &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), "Hello world".to_owned());
|
|
||||||
/// assert_eq!(16 * 8, stream.pos());
|
|
||||||
/// // null terminated
|
|
||||||
/// stream.set_pos(0);
|
|
||||||
/// let result = stream.read_string_into(None, &mut output)?;
|
|
||||||
/// assert_eq!(result.as_ref(&output), "Hello world".to_owned());
|
|
||||||
/// assert_eq!(12 * 8, stream.pos()); // 1 more for the terminating null byte
|
|
||||||
/// #
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`ReadError::NotEnoughData`]: enum.ReadError.html#variant.NotEnoughData
|
|
||||||
/// [`ReadError::Utf8Error`]: enum.ReadError.html#variant.Utf8Error
|
|
||||||
#[inline]
|
|
||||||
pub fn read_string_into(
|
|
||||||
&mut self,
|
|
||||||
byte_len: Option<usize>,
|
|
||||||
output: &mut String,
|
|
||||||
) -> Result<MaybeBorrowed<'a, str>> {
|
|
||||||
let max_length = self.bits_left() / 8;
|
let max_length = self.bits_left() / 8;
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.buffer
|
.buffer
|
||||||
.read_string_into(self.pos, byte_len, output)
|
.read_string(self.pos, byte_len)
|
||||||
.map_err(|mut err| {
|
.map_err(|mut err| {
|
||||||
// still advance the stream on malformed utf8
|
// still advance the stream on malformed utf8
|
||||||
if let BitError::Utf8Error(_, len) = &mut err {
|
if let BitError::Utf8Error(_, len) = &mut err {
|
||||||
self.pos += match byte_len {
|
self.pos += match byte_len {
|
||||||
Some(len) => len * 8,
|
Some(len) => len * 8,
|
||||||
None => min((*len + 1) * 8, max_length * 8),
|
None => min(*len + 1, max_length) * 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
*len = (*len).min(max_length);
|
*len = (*len).min(max_length);
|
||||||
|
|
@ -443,10 +324,9 @@ where
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let str = result.as_ref(output);
|
|
||||||
let read = match byte_len {
|
let read = match byte_len {
|
||||||
Some(len) => len * 8,
|
Some(len) => len * 8,
|
||||||
None => (str.len() + 1).min(max_length) * 8,
|
None => (result.len() + 1).min(max_length) * 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.pos += read;
|
self.pos += read;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue