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

prepare for 2024 edition compat

This commit is contained in:
Robin Appelman 2026-08-01 16:43:00 +02:00
commit b9330db6fa
3 changed files with 90 additions and 95 deletions

View file

@ -96,6 +96,8 @@ pub trait BitRead<'a, E: Endianness>: Sized {
/// Note: only the bounds are unchecked
///
/// any other validations (e.g. checking for valid utf8) still needs to be done
///
/// SAFETY: the caller is required to check the bounds of the read
#[doc(hidden)]
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<'a, E>, _end: bool) -> Result<Self> {
@ -131,7 +133,7 @@ macro_rules! impl_read_int {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<E>, end: bool) -> Result<$type> {
Ok(stream.read_int_unchecked::<$type>(<$type>::BITS as usize, end))
Ok(unsafe { stream.read_int_unchecked::<$type>(<$type>::BITS as usize, end) })
}
#[inline]
@ -155,9 +157,9 @@ macro_rules! impl_read_int_nonzero {
stream: &mut BitReadStream<LittleEndian>,
end: bool,
) -> Result<Self> {
Ok(<$type>::new(
stream.read_int_unchecked(size_of::<$type>() * 8, end),
))
Ok(<$type>::new(unsafe {
stream.read_int_unchecked(size_of::<$type>() * 8, end)
}))
}
#[inline]
@ -177,9 +179,9 @@ macro_rules! impl_read_int_nonzero {
stream: &mut BitReadStream<BigEndian>,
end: bool,
) -> Result<Self> {
Ok(<$type>::new(
stream.read_int_unchecked(size_of::<$type>() * 8, end),
))
Ok(<$type>::new(unsafe {
stream.read_int_unchecked(size_of::<$type>() * 8, end)
}))
}
#[inline]
@ -215,7 +217,7 @@ impl<E: Endianness> BitRead<'_, E> for f32 {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<E>, end: bool) -> Result<f32> {
Ok(stream.read_float_unchecked::<f32>(end))
Ok(unsafe { stream.read_float_unchecked::<f32>(end) })
}
#[inline]
@ -232,7 +234,7 @@ impl<E: Endianness> BitRead<'_, E> for f64 {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<E>, end: bool) -> Result<f64> {
Ok(stream.read_float_unchecked::<f64>(end))
Ok(unsafe { stream.read_float_unchecked::<f64>(end) })
}
#[inline]
@ -249,7 +251,7 @@ impl<E: Endianness> BitRead<'_, E> for bool {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<E>, _end: bool) -> Result<bool> {
Ok(stream.read_bool_unchecked())
Ok(unsafe { stream.read_bool_unchecked() })
}
#[inline]
@ -280,7 +282,7 @@ impl<'a, E: Endianness, T: BitRead<'a, E>> BitRead<'a, E> for Rc<T> {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<'a, E>, end: bool) -> Result<Self> {
Ok(Rc::new(T::read_unchecked(stream, end)?))
Ok(Rc::new(unsafe { T::read_unchecked(stream, end)? }))
}
#[inline]
@ -297,7 +299,7 @@ impl<'a, E: Endianness, T: BitRead<'a, E>> BitRead<'a, E> for Arc<T> {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<'a, E>, end: bool) -> Result<Self> {
Ok(Arc::new(T::read_unchecked(stream, end)?))
Ok(Arc::new(unsafe { T::read_unchecked(stream, end)? }))
}
#[inline]
@ -314,7 +316,7 @@ impl<'a, E: Endianness, T: BitRead<'a, E>> BitRead<'a, E> for Box<T> {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<'a, E>, end: bool) -> Result<Self> {
Ok(Box::new(T::read_unchecked(stream, end)?))
Ok(Box::new(unsafe { T::read_unchecked(stream, end)? }))
}
#[inline]
@ -333,7 +335,7 @@ macro_rules! impl_read_tuple {
#[inline]
unsafe fn read_unchecked(stream: &mut BitReadStream<'a, E>, end: bool) -> Result<Self> {
Ok(($(<$type>::read_unchecked(stream, end)?),*))
Ok(($(unsafe {<$type>::read_unchecked(stream, end)?}),*))
}
#[inline]
@ -348,6 +350,31 @@ impl_read_tuple!(T1, T2);
impl_read_tuple!(T1, T2, T3);
impl_read_tuple!(T1, T2, T3, T4);
/// Extracts the values from an array of `MaybeUninit` containers.
///
/// # Safety
///
/// It is up to the caller to guarantee that all elements of the array are
/// in an initialized state.
unsafe fn assume_init_array<T, const N: usize>(maybe_uninit: [MaybeUninit<T>; N]) -> [T; N] {
// to be replaced with `From<[MaybeUninit<T>; N]> for MaybeUninit<[T; N]>` and a normal `assume_init`
// once the MSRV is 1.95
unsafe { (&maybe_uninit as *const _ as *const [T; N]).read() }
}
/// Read an array item by item
fn ready_array<T, E, const N: usize>(
mut read_item: impl FnMut() -> Result<T, E>,
) -> Result<[T; N], E> {
let mut array = [const { <MaybeUninit<T>>::uninit() }; N];
for item in array.iter_mut() {
let val = read_item()?;
item.write(val);
}
// SAFETY: we initialized all items in the loop
Ok(unsafe { assume_init_array(array) })
}
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> {
@ -356,34 +383,16 @@ impl<'a, E: Endianness, T: BitRead<'a, E>, const N: usize> BitRead<'a, E> for [T
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 item in array.iter_mut() {
unsafe {
// length is already checked
let val = stream.read()?;
item.as_mut_ptr().write(val)
}
}
unsafe { Ok((&array as *const _ as *const [T; N]).read()) }
}
None => ready_array(|| stream.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 item in array.iter_mut() {
// length is already checked
let val = stream.read_unchecked(end)?;
item.as_mut_ptr().write(val);
}
Ok((&array as *const _ as *const [T; N]).read())
ready_array(|| {
// SAFETY: the caller is required to have checked the bounds
unsafe { stream.read_unchecked(end) }
})
}
#[inline]
@ -459,6 +468,7 @@ pub trait BitReadSized<'a, E: Endianness>: Sized {
/// Read the type from stream
fn read(stream: &mut BitReadStream<'a, E>, size: usize) -> Result<Self>;
/// SAFETY: the caller is required to check the bounds of the read
#[doc(hidden)]
#[inline]
unsafe fn read_unchecked(
@ -502,7 +512,7 @@ macro_rules! impl_read_int_sized {
size: usize,
end: bool,
) -> Result<$type> {
Ok(stream.read_int_unchecked::<$type>(size, end))
Ok(unsafe { stream.read_int_unchecked::<$type>(size, end) })
}
#[inline]
@ -626,7 +636,7 @@ impl<'a, E: Endianness, T: BitRead<'a, E>> BitReadSized<'a, E> for Vec<T> {
) -> Result<Self> {
let mut vec = Vec::with_capacity(min(size, 128));
for _ in 0..size {
vec.push(stream.read_unchecked(end)?)
vec.push(unsafe { stream.read_unchecked(end)? })
}
Ok(vec)
}
@ -668,8 +678,8 @@ impl<'a, E: Endianness, K: BitRead<'a, E> + Eq + Hash, T: BitRead<'a, E>> BitRea
) -> Result<Self> {
let mut map = HashMap::with_capacity(min(size, 128));
for _ in 0..size {
let key = stream.read_unchecked(end)?;
let value = stream.read_unchecked(end)?;
let key = unsafe { stream.read_unchecked(end)? };
let value = unsafe { stream.read_unchecked(end)? };
map.insert(key, value);
}
Ok(map)
@ -765,7 +775,7 @@ impl<'a, E: Endianness, T: BitReadSized<'a, E>> BitReadSized<'a, E> for Arc<T> {
size: usize,
end: bool,
) -> Result<Self> {
Ok(Arc::new(T::read_unchecked(stream, size, end)?))
Ok(Arc::new(unsafe { T::read_unchecked(stream, size, end)? }))
}
#[inline]
@ -786,7 +796,7 @@ impl<'a, E: Endianness, T: BitReadSized<'a, E>> BitReadSized<'a, E> for Rc<T> {
size: usize,
end: bool,
) -> Result<Self> {
Ok(Rc::new(T::read_unchecked(stream, size, end)?))
Ok(Rc::new(unsafe { T::read_unchecked(stream, size, end)? }))
}
#[inline]
@ -807,7 +817,7 @@ impl<'a, E: Endianness, T: BitReadSized<'a, E>> BitReadSized<'a, E> for Box<T> {
size: usize,
end: bool,
) -> Result<Self> {
Ok(Box::new(T::read_unchecked(stream, size, end)?))
Ok(Box::new(unsafe { T::read_unchecked(stream, size, end)? }))
}
#[inline]
@ -824,19 +834,7 @@ impl<'a, E: Endianness, T: BitReadSized<'a, E>, const N: usize> BitReadSized<'a,
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 item in array.iter_mut() {
unsafe {
// length is already checked
let val = stream.read_sized(size)?;
item.as_mut_ptr().write(val)
}
}
unsafe { Ok((&array as *const _ as *const [T; N]).read()) }
}
None => ready_array(|| stream.read_sized(size)),
}
}
@ -846,16 +844,10 @@ impl<'a, E: Endianness, T: BitReadSized<'a, E>, const N: usize> BitReadSized<'a,
size: usize,
end: bool,
) -> Result<Self> {
// SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
let mut array = MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init();
for item in array.iter_mut() {
// length is already checked
let val = stream.read_sized_unchecked(size, end)?;
item.as_mut_ptr().write(val);
}
Ok((&array as *const _ as *const [T; N]).read())
ready_array(|| {
// SAFETY: the caller is required to have checked the bounds
unsafe { stream.read_sized_unchecked(size, end) }
})
}
#[inline]

View file

@ -243,24 +243,27 @@ where
if end {
let mut bytes = [0; USIZE_SIZE];
let count = min(USIZE_SIZE, self.slice.len() - byte_index);
bytes[0..count]
.copy_from_slice(self.slice.get_unchecked(byte_index..byte_index + count));
bytes[0..count].copy_from_slice(unsafe {
self.slice.get_unchecked(byte_index..byte_index + count)
});
bytes
} else {
debug_assert!(byte_index + USIZE_SIZE <= self.slice.len());
// this is safe because all calling paths check that byte_index is less than the unpadded
// length (because they check based on bit_len), so with padding byte_index + USIZE_SIZE is
// always within bounds
unsafe {
self.slice
.get_unchecked(byte_index..byte_index + USIZE_SIZE)
.try_into()
.unwrap()
}
}
}
/// note that only the bottom USIZE - 1 bytes are usable
unsafe fn read_shifted_usize(&self, byte_index: usize, shift: usize, end: bool) -> usize {
let raw_bytes: [u8; USIZE_SIZE] = self.read_usize_bytes(byte_index, end);
let raw_bytes: [u8; USIZE_SIZE] = unsafe { self.read_usize_bytes(byte_index, end) };
let raw_usize: usize = usize::from_le_bytes(raw_bytes);
raw_usize >> shift
}
@ -269,7 +272,7 @@ where
let byte_index = position / 8;
let bit_offset = position & 7;
let bytes: [u8; USIZE_SIZE] = self.read_usize_bytes(byte_index, end);
let bytes: [u8; USIZE_SIZE] = unsafe { self.read_usize_bytes(byte_index, end) };
let container = if E::is_le() {
usize::from_le_bytes(bytes)
@ -339,7 +342,7 @@ where
let byte_index = position / 8;
let bit_offset = position & 7;
let byte = self.slice.get_unchecked(byte_index);
let byte = unsafe { self.slice.get_unchecked(byte_index) };
if E::is_le() {
let shifted = byte >> bit_offset;
shifted & 1u8 == 1
@ -410,9 +413,9 @@ where
let fit_usize = count + bit_offset < usize::BITS as usize;
let value = if fit_usize {
self.read_fit_usize(position, count, end)
unsafe { self.read_fit_usize(position, count, end) }
} else {
self.read_no_fit_usize(position, count, end)
unsafe { self.read_no_fit_usize(position, count, end) }
};
if count == type_bit_size {
@ -427,7 +430,7 @@ where
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let raw = self.read_usize(position, count, end);
let raw = unsafe { self.read_usize(position, count, end) };
T::from_unchecked(raw)
}
@ -443,7 +446,7 @@ where
while left_to_read > 0 {
let bits_left = self.bit_len() - read_pos;
let read = min(min(left_to_read, max_read), bits_left);
let data = T::from_unchecked(self.read_usize(read_pos, read, end));
let data = T::from_unchecked(unsafe { self.read_usize(read_pos, read, end) });
if E::is_le() {
acc |= data << bit_offset;
} else {
@ -528,7 +531,7 @@ where
if E::is_le() {
while byte_left > USIZE_SIZE - 1 {
let raw = self.read_shifted_usize(read_pos, shift, false);
let raw = unsafe { self.read_shifted_usize(read_pos, shift, false) };
let bytes = raw.to_le_bytes();
let read_bytes = USIZE_SIZE - 1;
let usable_bytes = &bytes[0..read_bytes];
@ -538,13 +541,13 @@ where
byte_left -= read_bytes;
}
let bytes = self.read_shifted_usize(read_pos, shift, true).to_le_bytes();
let bytes = unsafe { self.read_shifted_usize(read_pos, shift, true).to_le_bytes() };
let usable_bytes = &bytes[0..byte_left];
output.extend_from_slice(usable_bytes);
} else {
let mut pos = position;
while byte_left > 0 {
output.push(self.read_int_unchecked::<u8>(pos, 8, true));
output.push(unsafe { self.read_int_unchecked::<u8>(pos, 8, true) });
byte_left -= 1;
pos += 8;
}
@ -562,7 +565,7 @@ where
}
let mut output = Vec::with_capacity(byte_count);
self.read_bytes_unchecked_owned(position, byte_count, &mut output);
unsafe { self.read_bytes_unchecked_owned(position, byte_count, &mut output) };
Cow::Owned(output)
}
@ -770,7 +773,7 @@ where
.unwrap();
T::from_bytes::<E>(bytes)
} else {
let int = self.read_int_unchecked(position, size_of::<T>() * 8, end);
let int = unsafe { self.read_int_unchecked(position, size_of::<T>() * 8, end) };
T::from_int(int)
}
}

View file

@ -104,7 +104,7 @@ where
#[doc(hidden)]
#[inline]
pub unsafe fn read_bool_unchecked(&mut self) -> bool {
let result = self.buffer.read_bool_unchecked(self.pos);
let result = unsafe { self.buffer.read_bool_unchecked(self.pos) };
self.pos += 1;
result
}
@ -156,7 +156,7 @@ where
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + WrappingSub,
{
let result = self.buffer.read_int_unchecked(self.pos, count, end);
let result = unsafe { self.buffer.read_int_unchecked(self.pos, count, end) };
self.pos += count;
result
}
@ -207,7 +207,7 @@ where
T: Float + UncheckedPrimitiveFloat,
{
let count = size_of::<T>() * 8;
let result = self.buffer.read_float_unchecked(self.pos, end);
let result = unsafe { self.buffer.read_float_unchecked(self.pos, end) };
self.pos += count;
result
}
@ -255,7 +255,7 @@ where
#[inline]
pub unsafe fn read_bytes_unchecked(&mut self, byte_count: usize) -> Cow<'a, [u8]> {
let count = byte_count * 8;
let result = self.buffer.read_bytes_unchecked(self.pos, byte_count);
let result = unsafe { self.buffer.read_bytes_unchecked(self.pos, byte_count) };
self.pos += count;
result
}
@ -623,7 +623,7 @@ where
#[doc(hidden)]
#[inline]
pub unsafe fn read_unchecked<T: BitRead<'a, E>>(&mut self, end: bool) -> Result<T> {
T::read_unchecked(self, end)
unsafe { T::read_unchecked(self, end) }
}
/// Read a value based on the provided type and size
@ -695,7 +695,7 @@ where
size: usize,
end: bool,
) -> Result<T> {
T::read_unchecked(self, size, end)
unsafe { T::read_unchecked(self, size, end) }
}
/// Check if we can read a number of bits from the stream
@ -862,14 +862,14 @@ impl<'a, E: Endianness> schemars::JsonSchema for BitReadStream<'a, E> {
"BitReadStream".into()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
#[derive(schemars::JsonSchema)]
#[allow(dead_code)]
struct StreamSchema {
data: Vec<u8>,
bit_length: usize,
}
StreamSchema::json_schema(gen)
StreamSchema::json_schema(generator)
}
}
@ -879,7 +879,7 @@ impl<'a, E: Endianness> schemars_1::JsonSchema for BitReadStream<'a, E> {
"BitReadStream".into()
}
fn json_schema(gen: &mut schemars_1::SchemaGenerator) -> schemars_1::Schema {
fn json_schema(generator: &mut schemars_1::SchemaGenerator) -> schemars_1::Schema {
use schemars_1 as schemars;
#[derive(schemars_1::JsonSchema)]
@ -888,6 +888,6 @@ impl<'a, E: Endianness> schemars_1::JsonSchema for BitReadStream<'a, E> {
data: Vec<u8>,
bit_length: usize,
}
StreamSchema::json_schema(gen)
StreamSchema::json_schema(generator)
}
}