1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 16:44:06 +02:00

better IntoBytes

This commit is contained in:
Robin Appelman 2020-02-15 14:46:42 +01:00
commit bce35aeb32
2 changed files with 83 additions and 32 deletions

View file

@ -196,15 +196,69 @@ macro_rules! impl_is_signed {
} }
pub trait IntoBytes: Sized { pub trait IntoBytes: Sized {
fn into_bytes(self) -> Vec<u8>; type Iter: DoubleEndedIterator<Item = u8> + ExactSizeIterator;
fn into_bytes(self) -> Self::Iter;
} }
macro_rules! impl_into_bytes { macro_rules! impl_into_bytes {
($type:ty) => { ($type:ty, $iter:ident) => {
// once std::array:IntoIter is stabilized we can get rid of this iterator
// https://github.com/rust-lang/rust/issues/65798
pub struct $iter {
data: [u8; std::mem::size_of::<$type>()],
start: usize,
end: usize,
}
impl $iter {
pub fn new(int: $type) -> Self {
$iter {
data: int.to_le_bytes(),
start: 0,
end: std::mem::size_of::<$type>(),
}
}
}
impl Iterator for $iter {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if self.start < self.end {
let byte = self.data[self.start];
self.start += 1;
Some(byte)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.end - self.start;
(size, Some(size))
}
}
impl std::iter::DoubleEndedIterator for $iter {
fn next_back(&mut self) -> Option<Self::Item> {
if self.end > self.start {
self.end -= 1;
Some(self.data[self.end])
} else {
None
}
}
}
impl std::iter::ExactSizeIterator for $iter {}
impl IntoBytes for $type { impl IntoBytes for $type {
type Iter = $iter;
#[inline(always)] #[inline(always)]
fn into_bytes(self) -> Vec<u8> { fn into_bytes(self) -> Self::Iter {
self.to_le_bytes().to_vec() <$iter>::new(self)
} }
} }
}; };
@ -223,15 +277,15 @@ impl_is_signed!(i64, true);
impl_is_signed!(i128, true); impl_is_signed!(i128, true);
impl_is_signed!(isize, true); impl_is_signed!(isize, true);
impl_into_bytes!(u8); impl_into_bytes!(u8, BytesIterU8);
impl_into_bytes!(u16); impl_into_bytes!(u16, BytesIterU16);
impl_into_bytes!(u32); impl_into_bytes!(u32, BytesIterU32);
impl_into_bytes!(u64); impl_into_bytes!(u64, BytesIterU64);
impl_into_bytes!(u128); impl_into_bytes!(u128, BytesIterU128);
impl_into_bytes!(usize); impl_into_bytes!(usize, BytesIterUsize);
impl_into_bytes!(i8); impl_into_bytes!(i8, BytesIterI8);
impl_into_bytes!(i16); impl_into_bytes!(i16, BytesIterI16);
impl_into_bytes!(i32); impl_into_bytes!(i32, BytesIterI32);
impl_into_bytes!(i64); impl_into_bytes!(i64, BytesIterI64);
impl_into_bytes!(i128); impl_into_bytes!(i128, BytesIterI128);
impl_into_bytes!(isize); impl_into_bytes!(isize, BytesIterIsize);

View file

@ -1,15 +1,12 @@
use std::cmp::min; use num_traits::{Float, PrimInt};
use std::iter::{once, repeat};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::size_of; use std::mem::size_of;
use std::ops::{BitOrAssign, BitXor}; use std::ops::{BitOrAssign, BitXor};
use num_traits::{Float, PrimInt};
use crate::endianness::Endianness; use crate::endianness::Endianness;
use crate::num_traits::{IntoBytes, IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt}; use crate::num_traits::{IntoBytes, IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::readbuffer::get_bits_from_usize; use crate::{ReadError, Result};
use crate::{LittleEndian, ReadError, Result};
use std::iter::{once, repeat};
const USIZE_SIZE: usize = size_of::<usize>(); const USIZE_SIZE: usize = size_of::<usize>();
const USIZE_BITS: usize = USIZE_SIZE * 8; const USIZE_BITS: usize = USIZE_SIZE * 8;
@ -77,20 +74,20 @@ where
self.bytes.len() self.bytes.len()
} }
fn push_non_fit_bits(&mut self, bits: &[u8], count: usize) { fn push_non_fit_bits<I>(&mut self, bits: I, count: usize)
where
I: ExactSizeIterator,
I: DoubleEndedIterator<Item = u8>,
{
debug_assert!(bits.len() == count / 8); debug_assert!(bits.len() == count / 8);
let counts = repeat(8) let counts = repeat(8)
.take(bits.len() - 1) .take(bits.len() - 1)
.chain(once(count - (bits.len() - 1) * 8)); .chain(once(count - (bits.len() - 1) * 8));
if E::is_le() { if E::is_le() {
bits.iter() bits.zip(counts)
.copied()
.zip(counts)
.for_each(|(chunk, count)| self.push_bits(chunk as usize, count)) .for_each(|(chunk, count)| self.push_bits(chunk as usize, count))
} else { } else {
bits.iter() bits.rev()
.rev()
.copied()
.zip(counts) .zip(counts)
.for_each(|(chunk, count)| self.push_bits(chunk as usize, count)) .for_each(|(chunk, count)| self.push_bits(chunk as usize, count))
} }
@ -176,7 +173,7 @@ where
self.push_bits(value.into_usize_unchecked(), count); self.push_bits(value.into_usize_unchecked(), count);
} }
} else { } else {
self.push_non_fit_bits(&value.into_bytes(), count) self.push_non_fit_bits(value.into_bytes(), count)
} }
Ok(()) Ok(())
@ -207,10 +204,10 @@ where
if size_of::<T>() < USIZE_SIZE { if size_of::<T>() < USIZE_SIZE {
self.push_bits(value.to_f32().unwrap().to_bits() as usize, 32); self.push_bits(value.to_f32().unwrap().to_bits() as usize, 32);
} else { } else {
self.push_non_fit_bits(&value.to_f32().unwrap().to_le_bytes(), 32) self.push_non_fit_bits(value.to_f32().unwrap().to_bits().into_bytes(), 32)
}; };
} else { } else {
self.push_non_fit_bits(&value.to_f64().unwrap().to_le_bytes(), 64) self.push_non_fit_bits(value.to_f64().unwrap().to_bits().into_bytes(), 64)
} }
Ok(()) Ok(())