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

read/write array

This commit is contained in:
Robin Appelman 2021-07-13 19:37:10 +02:00
commit 1fadf092cf
3 changed files with 119 additions and 1 deletions

View file

@ -6,7 +6,7 @@ use std::cmp::min;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::size_of; use std::mem::{size_of, MaybeUninit};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -349,6 +349,50 @@ impl_read_tuple!(T1, T2);
impl_read_tuple!(T1, T2, T3); impl_read_tuple!(T1, T2, T3);
impl_read_tuple!(T1, T2, T3, T4); impl_read_tuple!(T1, T2, T3, T4);
impl<'a, E: Endianness, T: BitRead<'a, E>, const N: usize> BitRead<'a, E> for [T; N] {
#[inline]
fn read(stream: &mut BitReadStream<'a, E>) -> Result<Self> {
match T::bit_size() {
Some(bit_size) => {
let end = stream.check_read(bit_size * N)?;
unsafe { Self::read_unchecked(stream, end) }
}
None => {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
let mut array =
unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() };
for i in 0..N {
unsafe {
// length is already checked
let val = stream.read()?;
array[i].as_mut_ptr().write(val)
}
}
unsafe { Ok((&array as *const _ as *const [T; N]).read()) }
}
}
}
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<'a, E>, end: bool) -> Result<Self> {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
let mut array = MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init();
for i in 0..N {
// length is already checked
let val = stream.read_unchecked(end)?;
array[i].as_mut_ptr().write(val);
}
Ok((&array as *const _ as *const [T; N]).read())
}
#[inline]
fn bit_size() -> Option<usize> {
T::bit_size().map(|size| size * N)
}
}
/// Trait for types that can be read from a stream, requiring the size to be configured /// Trait for types that can be read from a stream, requiring the size to be configured
/// ///
/// The meaning of the set sized depends on the type being read (e.g, number of bits for integers, /// The meaning of the set sized depends on the type being read (e.g, number of bits for integers,
@ -710,3 +754,51 @@ impl<'a, T: BitReadSized<'a, E>, E: Endianness> BitReadSized<'a, E> for LazyBitR
T::bit_size_sized(size) T::bit_size_sized(size)
} }
} }
impl<'a, E: Endianness, T: BitReadSized<'a, E>, const N: usize> BitReadSized<'a, E> for [T; N] {
#[inline]
fn read(stream: &mut BitReadStream<'a, E>, size: usize) -> Result<Self> {
match T::bit_size_sized(size) {
Some(bit_size) => {
let end = stream.check_read(bit_size * N)?;
unsafe { Self::read_unchecked(stream, size, end) }
}
None => {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
let mut array =
unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() };
for i in 0..N {
unsafe {
// length is already checked
let val = stream.read_sized(size)?;
array[i].as_mut_ptr().write(val)
}
}
unsafe { Ok((&array as *const _ as *const [T; N]).read()) }
}
}
}
#[inline]
unsafe fn read_unchecked(
stream: &mut BitReadStream<'a, E>,
size: usize,
end: bool,
) -> Result<Self> {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
let mut array = MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init();
for i in 0..N {
// length is already checked
let val = stream.read_sized_unchecked(size, end)?;
array[i].as_mut_ptr().write(val);
}
Ok((&array as *const _ as *const [T; N]).read())
}
#[inline]
fn bit_size_sized(size: usize) -> Option<usize> {
T::bit_size_sized(size).map(|size| size * N)
}
}

View file

@ -71,6 +71,16 @@ impl<E: Endianness> BitWrite<E> for BitReadStream<'_, E> {
} }
} }
impl<E: Endianness, T: BitWrite<E>, const N: usize> BitWrite<E> for [T; N] {
#[inline]
fn write(&self, stream: &mut BitWriteStream<E>) -> Result<()> {
for element in self.iter() {
stream.write(element)?;
}
Ok(())
}
}
/// Trait for types that can be written to a stream, requiring the size to be configured /// Trait for types that can be written to a stream, requiring the size to be configured
pub trait BitWriteSized<E: Endianness> { pub trait BitWriteSized<E: Endianness> {
/// Write the type to stream /// Write the type to stream
@ -120,3 +130,13 @@ impl<E: Endianness> BitWriteSized<E> for BitReadStream<'_, E> {
stream.write_bits(&bits) stream.write_bits(&bits)
} }
} }
impl<E: Endianness, T: BitWriteSized<E>, const N: usize> BitWriteSized<E> for [T; N] {
#[inline]
fn write_sized(&self, stream: &mut BitWriteStream<E>, len: usize) -> Result<()> {
for element in self.iter() {
stream.write_sized(element, len)?;
}
Ok(())
}
}

View file

@ -90,3 +90,9 @@ fn test_field_enum() {
roundtrip(Enum::C(12.0)); roundtrip(Enum::C(12.0));
roundtrip(Enum::D(-12345)); roundtrip(Enum::D(-12345));
} }
#[test]
fn test_array() {
roundtrip([1, 2, 3, 4, 5]);
roundtrip([String::from("asd"), String::from("foobar")]);
}