use core::convert::TryInto;
#[cfg(feature = "bits")]
use bitvec::prelude::*;
use no_std_io::io::{Read, Seek, Write};
use crate::ctx::*;
use crate::reader::{Reader, ReaderRet};
use crate::writer::Writer;
use crate::{deku_error, DekuError, DekuReader, DekuWriter};
#[cfg(feature = "bits")]
trait DekuRead<'a, Ctx = ()> {
fn read(
input: &'a crate::bitvec::BitSlice<u8, crate::bitvec::Msb0>,
ctx: Ctx,
) -> Result<(usize, Self), DekuError>
where
Self: Sized;
}
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize)> for u8 {
#[inline]
fn read(
input: &BitSlice<u8, Msb0>,
(_, _): (Endian, ByteSize),
) -> Result<(usize, Self), DekuError> {
const MAX_TYPE_BITS: usize = BitSize::of::<u8>().0;
let value = input[..MAX_TYPE_BITS].load::<u8>();
Ok((MAX_TYPE_BITS, value))
}
}
impl DekuReader<'_, (Endian, ByteSize, Order)> for u8 {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(_endian, _size, order): (Endian, ByteSize, Order),
) -> Result<u8, DekuError> {
const MAX_TYPE_BYTES: usize = core::mem::size_of::<u8>();
let mut buf = [0; MAX_TYPE_BYTES];
reader.read_bytes_const_into::<MAX_TYPE_BYTES>(&mut buf, order)?;
Ok(<u8>::from_be_bytes(buf))
}
}
#[cfg(feature = "bits")]
impl DekuWriter<(Endian, BitSize)> for u8 {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(_, bit_size): (Endian, BitSize),
) -> Result<(), DekuError> {
<u8>::to_writer(self, writer, (Endian::Big, bit_size, Order::default()))
}
}
#[cfg(feature = "bits")]
impl DekuWriter<(Endian, BitSize, Order)> for u8 {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(_, size, order): (Endian, BitSize, Order),
) -> Result<(), DekuError> {
let input = self.to_le_bytes();
let bit_size: usize = size.0;
let input_bits = input.view_bits::<Msb0>();
if bit_size > input_bits.len() {
return Err(deku_error!(
DekuError::InvalidParam,
"Bit size is larger than input",
"{} exceeds {}",
bit_size,
input_bits.len()
));
}
const MAX_TYPE_BITS: usize = BitSize::of::<u8>().0;
if let Some(first) = input_bits.first_one() {
let max = MAX_TYPE_BITS - bit_size;
if max > first {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than bit requested size",
"{} exceeds {}",
MAX_TYPE_BITS - first,
bit_size
));
}
}
writer.write_bits_order(&input_bits[input_bits.len() - bit_size..], order)?;
Ok(())
}
}
impl DekuWriter<(Endian, ByteSize, Order)> for u8 {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(_, _, _): (Endian, ByteSize, Order),
) -> Result<(), DekuError> {
let input = self.to_le_bytes();
writer.write_bytes(&input)?;
Ok(())
}
}
impl DekuWriter<(Endian, ByteSize)> for u8 {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(_, _): (Endian, ByteSize),
) -> Result<(), DekuError> {
let input = self.to_le_bytes();
writer.write_bytes(&input)?;
Ok(())
}
}
macro_rules! ImplDekuReadBits {
($typ:ty, $inner:ty) => {
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, BitSize, Order)> for $typ {
#[inline]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size, order): (Endian, BitSize, Order),
) -> Result<(usize, Self), DekuError> {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
let bit_size: usize = size.0;
let input_is_le = endian.is_le();
let bit_slice = &input;
let pad = 8 * bit_slice.len().div_ceil(8) - bit_slice.len();
debug_assert!(MAX_TYPE_BITS >= bit_slice.len() + pad);
if pad == 0 && bit_slice.len() == MAX_TYPE_BITS {
let bytes = bit_slice.domain().region().unwrap().1;
if bytes.len() * 8 == MAX_TYPE_BITS {
let value = if input_is_le {
<$typ>::from_le_bytes(bytes.try_into()?)
} else {
<$typ>::from_be_bytes(bytes.try_into()?)
};
return Ok((bit_size, value));
}
}
debug_assert_eq!(bit_size, bit_slice.len());
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
if order == Order::Lsb0 && bit_slice.len() > 8 && pad != 0 {
let mut bits = crate::BoundedBitVec::<[u8; MAX_TYPE_BYTES], Msb0>::new();
bits.extend_from_bitslice(&bit_slice);
for _ in 0..pad {
bits.insert(0, false);
}
let mut buf = [0u8; MAX_TYPE_BYTES];
for (slice, slot) in bits.as_bitslice().rchunks_exact(8).zip(buf.iter_mut()) {
*slot = slice.load_be();
}
let value = if input_is_le {
<$typ>::from_le_bytes(buf.try_into().unwrap())
} else {
<$typ>::from_be_bytes(buf.try_into().unwrap())
};
Ok((bit_size, value))
} else {
let bits: crate::BoundedBitVec<[u8; MAX_TYPE_BYTES], Msb0> = {
let mut bits = crate::BoundedBitVec::new();
bits.extend_from_bitslice(&bit_slice);
let index = if input_is_le {
bits.len() - (8 - pad)
} else {
0
};
for _ in 0..pad {
bits.insert(index, false);
}
for _ in 0..(MAX_TYPE_BITS - bits.len()) {
if input_is_le {
bits.push(false);
} else {
bits.insert(0, false);
}
}
bits
};
let bytes = bits.as_raw_slice();
let value = if input_is_le {
<$typ>::from_le_bytes(bytes.try_into()?)
} else {
<$typ>::from_be_bytes(bytes.try_into()?)
};
Ok((bit_size, value))
}
}
}
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, BitSize)> for $typ {
#[inline(never)]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size): (Endian, BitSize),
) -> Result<(usize, Self), DekuError> {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
let bit_size: usize = size.0;
let input_is_le = endian.is_le();
let bit_slice = &input[..bit_size];
let pad = 8 * bit_slice.len().div_ceil(8) - bit_slice.len();
if pad == 0 && bit_slice.len() == MAX_TYPE_BITS {
let bytes = bit_slice.domain().region().unwrap().1;
if bytes.len() * 8 == MAX_TYPE_BITS {
let value = if input_is_le {
<$typ>::from_le_bytes(bytes.try_into()?)
} else {
<$typ>::from_be_bytes(bytes.try_into()?)
};
return Ok((bit_size, value));
}
}
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
let bits: crate::BoundedBitVec<[u8; MAX_TYPE_BYTES], Msb0> = {
let mut bits = crate::BoundedBitVec::new();
bits.extend_from_bitslice(&bit_slice);
let index = if input_is_le {
bits.len() - (8 - pad)
} else {
0
};
for _ in 0..pad {
bits.insert(index, false);
}
for _ in 0..(MAX_TYPE_BITS - bits.len()) {
if input_is_le {
bits.push(false);
} else {
bits.insert(0, false);
}
}
bits
};
let bytes = bits.as_raw_slice();
let value = if input_is_le {
<$typ>::from_le_bytes(bytes.try_into()?)
} else {
<$typ>::from_be_bytes(bytes.try_into()?)
};
Ok((bit_size, value))
}
}
#[cfg(feature = "bits")]
impl DekuReader<'_, (Endian, BitSize)> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, size): (Endian, BitSize),
) -> Result<$typ, DekuError> {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
if size.0 > MAX_TYPE_BITS {
return Err(deku_error!(
DekuError::Parse,
"too much data",
"container of {} bits cannot hold {} bits",
MAX_TYPE_BITS,
size.0
));
}
let mut bits = ::bitvec::array::BitArray::<[u8; { MAX_TYPE_BITS / 8 }], Msb0>::new(
[0; { MAX_TYPE_BITS / 8 }],
);
reader.read_bits_into(&mut bits[..size.0], Order::default())?;
let a = <$typ>::read(&bits[..size.0], (endian, size))?;
Ok(a.1)
}
}
#[cfg(feature = "bits")]
impl DekuReader<'_, (Endian, BitSize, Order)> for $typ {
#[inline]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, size, order): (Endian, BitSize, Order),
) -> Result<$typ, DekuError> {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
if size.0 > MAX_TYPE_BITS {
return Err(deku_error!(
DekuError::Parse,
"too much data",
"container of {} cannot hold {} bits",
MAX_TYPE_BITS,
size.0
));
}
let mut bits = ::bitvec::array::BitArray::<[u8; { MAX_TYPE_BITS / 8 }], Msb0>::new(
[0; { MAX_TYPE_BITS / 8 }],
);
reader.read_bits_into(&mut bits[..size.0], order)?;
let a = <$typ>::read(&bits[..size.0], (endian, size, order))?;
Ok(a.1)
}
}
};
}
macro_rules! ImplDekuReadBytes {
($typ:ty, $inner:ty) => {
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize, Order)> for $typ {
#[inline]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size, order): (Endian, ByteSize, Order),
) -> Result<(usize, Self), DekuError> {
<$typ as DekuRead<'_, (Endian, BitSize, Order)>>::read(
input,
(endian, BitSize(size.0 * 8), order),
)
}
}
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize)> for $typ {
#[inline(never)]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size): (Endian, ByteSize),
) -> Result<(usize, Self), DekuError> {
let bit_size = BitSize(size.0 * 8);
<$typ>::read(input, (endian, bit_size))
}
}
impl DekuReader<'_, (Endian, ByteSize, Order)> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, size, order): (Endian, ByteSize, Order),
) -> Result<$typ, DekuError> {
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
if size.0 > MAX_TYPE_BYTES {
return Err(deku_error!(
DekuError::Parse,
"too much data",
"container of {} bytes cannot hold {} bytes",
MAX_TYPE_BYTES,
size.0
));
}
let mut buf = [0; MAX_TYPE_BYTES];
let ret = reader.read_bytes(size.0, &mut buf, order)?;
let a = match ret {
ReaderRet::Bytes => {
if endian.is_le() {
<$typ>::from_le_bytes(buf.try_into().unwrap())
} else {
if size.0 != core::mem::size_of::<$typ>() {
let padding = core::mem::size_of::<$typ>() - size.0;
buf.copy_within(0..size.0, padding);
buf[..padding].fill(0x00);
}
<$typ>::from_be_bytes(buf.try_into().unwrap())
}
}
#[cfg(all(feature = "bits", feature = "alloc"))]
ReaderRet::Bits(Some(bits)) => {
let a = <$typ>::read(&bits, (endian, size, order))?;
a.1
}
#[cfg(all(feature = "bits", feature = "alloc"))]
ReaderRet::Bits(None) => {
return Err(deku_error!(DekuError::Parse, "no bits read from reader"));
}
};
Ok(a)
}
}
};
}
macro_rules! ImplDekuReadSignExtend {
($typ:ty, $inner:ty) => {
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize, Order)> for $typ {
#[inline]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size, order): (Endian, ByteSize, Order),
) -> Result<(usize, Self), DekuError> {
<$typ as DekuRead<'_, (Endian, BitSize, Order)>>::read(
input,
(endian, BitSize(size.0 * 8), order),
)
}
}
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, BitSize, Order)> for $typ {
#[inline]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size, order): (Endian, BitSize, Order),
) -> Result<(usize, Self), DekuError> {
let (amt_read, value) = <$inner as DekuRead<'_, (Endian, BitSize, Order)>>::read(
input,
(endian, size, order),
)?;
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
let bit_size = size.0;
let shift = MAX_TYPE_BITS - bit_size;
let value = (value as $typ) << shift >> shift;
Ok((amt_read, value))
}
}
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, ByteSize)> for $typ {
#[inline(never)]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size): (Endian, ByteSize),
) -> Result<(usize, Self), DekuError> {
let (amt_read, value) =
<$inner as DekuRead<'_, (Endian, ByteSize)>>::read(input, (endian, size))?;
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
let bit_size = size.0 * 8;
let shift = MAX_TYPE_BITS - bit_size;
let value = (value as $typ) << shift >> shift;
Ok((amt_read, value))
}
}
#[cfg(feature = "bits")]
impl DekuRead<'_, (Endian, BitSize)> for $typ {
#[inline(never)]
fn read(
input: &BitSlice<u8, Msb0>,
(endian, size): (Endian, BitSize),
) -> Result<(usize, Self), DekuError> {
let (amt_read, value) =
<$inner as DekuRead<'_, (Endian, BitSize)>>::read(input, (endian, size))?;
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
let bit_size = size.0;
let shift = MAX_TYPE_BITS - bit_size;
let value = (value as $typ) << shift >> shift;
Ok((amt_read, value))
}
}
#[cfg(feature = "bits")]
impl DekuReader<'_, (Endian, BitSize)> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, size): (Endian, BitSize),
) -> Result<$typ, DekuError> {
<$typ>::from_reader_with_ctx(reader, (endian, size, Order::default()))
}
}
#[cfg(feature = "bits")]
impl DekuReader<'_, (Endian, BitSize, Order)> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, size, order): (Endian, BitSize, Order),
) -> Result<$typ, DekuError> {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
if size.0 > MAX_TYPE_BITS {
return Err(deku_error!(
DekuError::Parse,
"too much data",
"container of {} bits cannot hold {} bits",
MAX_TYPE_BITS,
size.0
));
}
let mut bits = ::bitvec::array::BitArray::<[u8; { MAX_TYPE_BITS / 8 }], Msb0>::new(
[0; { MAX_TYPE_BITS / 8 }],
);
reader.read_bits_into(&mut bits[..size.0], order)?;
let a = <$typ>::read(&bits[..size.0], (endian, size, order))?;
Ok(a.1)
}
}
impl DekuReader<'_, (Endian, ByteSize, Order)> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, size, order): (Endian, ByteSize, Order),
) -> Result<$typ, DekuError> {
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
if size.0 > MAX_TYPE_BYTES {
return Err(deku_error!(
DekuError::Parse,
"too much data",
"container of {} bytes cannot hold {} bytes",
MAX_TYPE_BYTES,
size.0
));
}
let mut buf = [0; MAX_TYPE_BYTES];
let ret = reader.read_bytes(size.0, &mut buf, order)?;
let a = match ret {
ReaderRet::Bytes => {
if endian.is_le() {
<$typ>::from_le_bytes(buf.try_into().unwrap())
} else {
if size.0 != core::mem::size_of::<$typ>() {
let padding = core::mem::size_of::<$typ>() - size.0;
buf.copy_within(0..size.0, padding);
buf[..padding].fill(0x00);
}
<$typ>::from_be_bytes(buf.try_into().unwrap())
}
}
#[cfg(all(feature = "bits", feature = "alloc"))]
ReaderRet::Bits(Some(bits)) => {
let a = <$typ>::read(&bits, (endian, size, order))?;
a.1
}
#[cfg(all(feature = "bits", feature = "alloc"))]
ReaderRet::Bits(None) => {
return Err(deku_error!(DekuError::Parse, "no bits read from reader"));
}
};
Ok(a)
}
}
};
}
macro_rules! ForwardDekuRead {
($typ:ty) => {
impl DekuReader<'_, (Endian, Order)> for $typ {
#[inline]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, order): (Endian, Order),
) -> Result<$typ, DekuError> {
let byte_size = core::mem::size_of::<$typ>();
<$typ>::from_reader_with_ctx(reader, (endian, ByteSize(byte_size), order))
}
}
impl DekuReader<'_, (Endian, ByteSize)> for $typ {
#[inline]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(endian, byte_size): (Endian, ByteSize),
) -> Result<$typ, DekuError> {
<$typ>::from_reader_with_ctx(reader, (endian, byte_size, Order::default()))
}
}
impl DekuReader<'_, Endian> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
endian: Endian,
) -> Result<$typ, DekuError> {
const MAX_TYPE_BYTES: usize = core::mem::size_of::<$typ>();
let mut buf = [0; MAX_TYPE_BYTES];
reader.read_bytes_const_into::<MAX_TYPE_BYTES>(&mut buf, Order::default())?;
if endian.is_le() {
Ok(<$typ>::from_le_bytes(buf))
} else {
Ok(<$typ>::from_be_bytes(buf))
}
}
}
impl DekuReader<'_, ByteSize> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
byte_size: ByteSize,
) -> Result<$typ, DekuError> {
let endian = Endian::default();
let a = <$typ>::from_reader_with_ctx(reader, (endian, byte_size))?;
Ok(a)
}
}
#[cfg(feature = "bits")]
impl DekuReader<'_, BitSize> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
bit_size: BitSize,
) -> Result<$typ, DekuError> {
let endian = Endian::default();
if (bit_size.0 % 8) == 0 {
<$typ>::from_reader_with_ctx(reader, (endian, ByteSize(bit_size.0 / 8)))
} else {
<$typ>::from_reader_with_ctx(reader, (endian, bit_size))
}
}
}
#[cfg(feature = "bits")]
impl DekuReader<'_, (BitSize, Order)> for $typ {
#[inline]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
(bit_size, order): (BitSize, Order),
) -> Result<$typ, DekuError> {
let endian = Endian::default();
if (bit_size.0 % 8) == 0 {
<$typ>::from_reader_with_ctx(reader, (endian, ByteSize(bit_size.0 / 8), order))
} else {
<$typ>::from_reader_with_ctx(reader, (endian, bit_size, order))
}
}
}
impl DekuReader<'_, Order> for $typ {
#[inline]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
order: Order,
) -> Result<$typ, DekuError> {
<$typ>::from_reader_with_ctx(reader, (Endian::default(), order))
}
}
impl DekuReader<'_> for $typ {
#[inline(always)]
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
_: (),
) -> Result<$typ, DekuError> {
<$typ>::from_reader_with_ctx(reader, Endian::default())
}
}
};
}
macro_rules! ImplDekuWrite {
($typ:ty, $signed_type:ident) => {
#[cfg(feature = "bits")]
impl DekuWriter<(Endian, BitSize, Order)> for $typ {
#[inline]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(endian, size, order): (Endian, BitSize, Order),
) -> Result<(), DekuError> {
let input = match endian {
Endian::Little => self.to_le_bytes(),
Endian::Big => self.to_be_bytes(),
};
let bit_size: usize = size.0;
let input_bits = input.view_bits::<Msb0>();
if bit_size > input_bits.len() {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size is larger than input",
"{} exceeds {}",
bit_size,
input_bits.len()
));
}
match (endian, order) {
(Endian::Little, Order::Lsb0) | (Endian::Little, Order::Msb0) => {
let input_bits_lsb = input.view_bits::<Lsb0>();
if let Some(last) = input_bits_lsb.last_one() {
let last = last + 1;
let max = bit_size;
if last > max {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than requested size",
"{} exceeds {}",
last,
bit_size
));
}
}
let mut remaining_bits = bit_size;
for chunk in input_bits.chunks(8) {
if chunk.len() > remaining_bits {
writer.write_bits_order(
&chunk[chunk.len() - remaining_bits..],
order,
)?;
break;
} else {
writer.write_bits_order(&chunk, order)?;
}
remaining_bits -= chunk.len();
}
}
(Endian::Big, Order::Lsb0) => {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
if let Some(first) = input_bits.first_one() {
let max = MAX_TYPE_BITS - bit_size;
if max > first {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than requested size",
"{} exceeds {}",
MAX_TYPE_BITS - first,
bit_size
));
}
}
if bit_size <= 8 {
writer.write_bits_order(
&input_bits[input_bits.len() - bit_size..],
order,
)?;
} else {
let mut remaining_bits = bit_size;
for chunk in input_bits.chunks(8) {
if chunk.len() > remaining_bits {
writer.write_bits_order(
&chunk[chunk.len() - remaining_bits..],
order,
)?;
break;
} else {
writer.write_bits_order(&chunk, order)?;
}
remaining_bits -= chunk.len();
}
}
}
(Endian::Big, Order::Msb0) => {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
if let Some(first) = input_bits.first_one() {
let max = MAX_TYPE_BITS - bit_size;
if max > first {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than requested size",
"{} exceeds {}",
MAX_TYPE_BITS - first,
bit_size
));
}
}
writer.write_bits_order(
&input_bits[input_bits.len() - bit_size..],
Order::Msb0,
)?;
}
}
Ok(())
}
}
ImplDekuWriteDetails!($typ, $signed_type);
impl DekuWriter<(Endian, ByteSize)> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(endian, size): (Endian, ByteSize),
) -> Result<(), DekuError> {
let input = match endian {
Endian::Little => self.to_le_bytes(),
Endian::Big => self.to_be_bytes(),
};
const TYPE_SIZE: usize = core::mem::size_of::<$typ>();
if size.0 > TYPE_SIZE {
return Err(deku_error!(
DekuError::InvalidParam,
"byte size is larger than input",
"{} exceeds {}",
size.0,
TYPE_SIZE
));
}
let input = if matches!(endian, Endian::Big) {
&input[TYPE_SIZE - size.0 as usize..]
} else {
&input[..size.0 as usize]
};
writer.write_bytes(&input)?;
Ok(())
}
}
impl DekuWriter<(Endian, ByteSize, Order)> for $typ {
#[inline]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(endian, size, _order): (Endian, ByteSize, Order),
) -> Result<(), DekuError> {
<$typ>::to_writer(self, writer, (endian, size))
}
}
};
}
macro_rules! ImplDekuWriteDetails {
($typ:ty, Unsigned) => {
#[cfg(feature = "bits")]
impl DekuWriter<(Endian, BitSize)> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(endian, size): (Endian, BitSize),
) -> Result<(), DekuError> {
let input = match endian {
Endian::Little => self.to_le_bytes(),
Endian::Big => self.to_be_bytes(),
};
let bit_size: usize = size.0;
let input_bits = input.view_bits::<Msb0>();
if bit_size > input_bits.len() {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size is larger than input",
"{} exceeds {}",
bit_size,
input_bits.len()
));
}
if matches!(endian, Endian::Little) {
let input_bits_lsb = input.view_bits::<Lsb0>();
if let Some(last) = input_bits_lsb.last_one() {
let last = last + 1;
let max = bit_size;
if last > max {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than requested size",
"{} exceeds {}",
last,
bit_size
));
}
}
let mut remaining_bits = bit_size;
for chunk in input_bits.chunks(8) {
if chunk.len() > remaining_bits {
writer.write_bits(&chunk[chunk.len() - remaining_bits..])?;
break;
} else {
writer.write_bits(&chunk)?;
}
remaining_bits -= chunk.len();
}
} else {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
if let Some(first) = input_bits.first_one() {
let max = (MAX_TYPE_BITS - bit_size);
if max > first {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than bit requested size",
"{} exceeds {}",
MAX_TYPE_BITS - first,
bit_size
));
}
}
writer.write_bits(&input_bits[input_bits.len() - bit_size..])?;
}
Ok(())
}
}
};
($typ:ty, Signed) => {
#[cfg(feature = "bits")]
impl DekuWriter<(Endian, BitSize)> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(endian, size): (Endian, BitSize),
) -> Result<(), DekuError> {
let input = match endian {
Endian::Little => self.to_le_bytes(),
Endian::Big => self.to_be_bytes(),
};
let bit_size: usize = size.0;
let input_bits = input.view_bits::<Msb0>();
if bit_size > input_bits.len() {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size is larger than input",
"{} exceeds {}",
bit_size,
input_bits.len()
));
}
if matches!(endian, Endian::Little) {
if *self >= 0 {
let input_bits_lsb = input.view_bits::<Lsb0>();
if let Some(last) = input_bits_lsb.last_one() {
let last = last + 2;
let max = bit_size;
if last > max {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than bit requested size",
"{} exceeds {}",
last,
bit_size
));
}
}
} else {
let input_bits_lsb = input.view_bits::<Lsb0>();
if let Some(last) = input_bits_lsb.last_zero() {
let last = last + 2;
let max = bit_size;
if last > max {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than requested bit size",
"{} exceeds {}",
last,
bit_size
));
}
}
}
let mut remaining_bits = bit_size;
for chunk in input_bits.chunks(8) {
if chunk.len() > remaining_bits {
writer.write_bits(&chunk[chunk.len() - remaining_bits..])?;
break;
} else {
writer.write_bits(&chunk)?;
}
remaining_bits -= chunk.len();
}
} else {
const MAX_TYPE_BITS: usize = BitSize::of::<$typ>().0;
if *self >= 0 {
if let Some(first) = input_bits.first_one() {
let max = (MAX_TYPE_BITS - bit_size);
if max + 1 > first {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than bit requested size",
"{} exceeds {}",
MAX_TYPE_BITS - first,
bit_size
));
}
}
} else {
if let Some(first) = input_bits.first_zero() {
let max = (MAX_TYPE_BITS - bit_size);
if max + 1 > first {
return Err(deku_error!(
DekuError::InvalidParam,
"bit size of input is larger than bit requested size",
"{} exceeds {}",
MAX_TYPE_BITS - first,
bit_size
));
}
}
}
writer.write_bits(&input_bits[input_bits.len() - bit_size..])?;
}
Ok(())
}
}
};
}
macro_rules! ImplDekuWriteOnlyEndian {
($typ:ty) => {
impl DekuWriter<Endian> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
endian: Endian,
) -> Result<(), DekuError> {
let input = match endian {
Endian::Little => self.to_le_bytes(),
Endian::Big => self.to_be_bytes(),
};
writer.write_bytes(&input)?;
Ok(())
}
}
};
}
macro_rules! ForwardDekuWrite {
($typ:ty) => {
#[cfg(feature = "bits")]
impl DekuWriter<(BitSize, Order)> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(bit_size, order): (BitSize, Order),
) -> Result<(), DekuError> {
<$typ>::to_writer(self, writer, (Endian::default(), bit_size, order))
}
}
impl DekuWriter<(Endian, Order)> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
(endian, order): (Endian, Order),
) -> Result<(), DekuError> {
let byte_size = core::mem::size_of::<$typ>();
<$typ>::to_writer(self, writer, (endian, ByteSize(byte_size), order))
}
}
#[cfg(feature = "bits")]
impl DekuWriter<BitSize> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
bit_size: BitSize,
) -> Result<(), DekuError> {
<$typ>::to_writer(self, writer, (Endian::default(), bit_size))
}
}
impl DekuWriter<ByteSize> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
byte_size: ByteSize,
) -> Result<(), DekuError> {
<$typ>::to_writer(self, writer, (Endian::default(), byte_size))
}
}
impl DekuWriter<Order> for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
order: Order,
) -> Result<(), DekuError> {
<$typ>::to_writer(self, writer, (Endian::default(), order))
}
}
impl DekuWriter for $typ {
#[inline(always)]
fn to_writer<W: Write + Seek>(
&self,
writer: &mut Writer<W>,
_: (),
) -> Result<(), DekuError> {
<$typ>::to_writer(self, writer, Endian::default())
}
}
};
}
macro_rules! ImplDekuTraitsBytesUnsigned {
($typ:ty) => {
ImplDekuReadBytes!($typ, $typ);
ImplDekuWrite!($typ, Unsigned);
};
($typ:ty, $inner:ty) => {
ImplDekuReadBytes!($typ, $inner);
};
}
macro_rules! ImplDekuTraitsUnsigned {
($typ:ty) => {
ImplDekuReadBits!($typ, $typ);
ForwardDekuRead!($typ);
ImplDekuWriteOnlyEndian!($typ);
ForwardDekuWrite!($typ);
};
($typ:ty, $inner:ty) => {
ImplDekuReadBits!($typ, $inner);
ForwardDekuRead!($typ);
ImplDekuWrite!($typ, Unsigned);
ImplDekuWriteOnlyEndian!($typ);
ForwardDekuWrite!($typ);
};
}
macro_rules! ImplDekuTraitsSigned {
($typ:ty, $inner:ty) => {
ImplDekuReadSignExtend!($typ, $inner);
ForwardDekuRead!($typ);
ImplDekuWrite!($typ, Signed);
ImplDekuWriteOnlyEndian!($typ);
ForwardDekuWrite!($typ);
};
}
ImplDekuTraitsUnsigned!(u8);
ImplDekuTraitsUnsigned!(u16);
ImplDekuTraitsBytesUnsigned!(u16);
ImplDekuTraitsUnsigned!(u32);
ImplDekuTraitsBytesUnsigned!(u32);
ImplDekuTraitsUnsigned!(u64);
ImplDekuTraitsBytesUnsigned!(u64);
ImplDekuTraitsUnsigned!(u128);
ImplDekuTraitsBytesUnsigned!(u128);
ImplDekuTraitsUnsigned!(usize);
ImplDekuTraitsBytesUnsigned!(usize);
ImplDekuTraitsSigned!(i8, u8);
ImplDekuTraitsSigned!(i16, u16);
ImplDekuTraitsSigned!(i32, u32);
ImplDekuTraitsSigned!(i64, u64);
ImplDekuTraitsSigned!(i128, u128);
ImplDekuTraitsSigned!(isize, usize);
ImplDekuTraitsUnsigned!(f32, u32);
ImplDekuTraitsBytesUnsigned!(f32, u32);
ImplDekuTraitsUnsigned!(f64, u64);
ImplDekuTraitsBytesUnsigned!(f64, u64);
use crate::DekuSize;
macro_rules! ImplDekuSize {
($typ:ty) => {
impl DekuSize for $typ {
const SIZE_BITS: usize = core::mem::size_of::<$typ>() * 8;
}
};
}
ImplDekuSize!(u8);
ImplDekuSize!(u16);
ImplDekuSize!(u32);
ImplDekuSize!(u64);
ImplDekuSize!(u128);
ImplDekuSize!(usize);
ImplDekuSize!(i8);
ImplDekuSize!(i16);
ImplDekuSize!(i32);
ImplDekuSize!(i64);
ImplDekuSize!(i128);
ImplDekuSize!(isize);
ImplDekuSize!(f32);
ImplDekuSize!(f64);
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use rstest::rstest;
use std::io::Cursor;
use super::*;
use crate::{native_endian, reader::Reader};
static ENDIAN: Endian = Endian::new();
macro_rules! TestPrimitive {
($test_name:ident, $typ:ty, $input:expr, $expected:expr) => {
#[test]
fn $test_name() {
let mut r = std::io::Cursor::new($input);
let mut reader = Reader::new(&mut r);
let res_read = <$typ>::from_reader_with_ctx(&mut reader, ENDIAN).unwrap();
assert_eq!($expected, res_read);
let mut writer = Writer::new(Cursor::new(vec![]));
res_read.to_writer(&mut writer, ENDIAN).unwrap();
assert_eq!($input, writer.inner.into_inner());
}
};
}
TestPrimitive!(test_u8, u8, vec![0xaau8], 0xaau8);
TestPrimitive!(
test_u16,
u16,
vec![0xabu8, 0xcd],
native_endian!(0xcdab_u16)
);
TestPrimitive!(
test_u32,
u32,
vec![0xabu8, 0xcd, 0xef, 0xbe],
native_endian!(0xbeefcdab_u32)
);
TestPrimitive!(
test_u64,
u64,
vec![0xabu8, 0xcd, 0xef, 0xbe, 0xab, 0xcd, 0xfe, 0xc0],
native_endian!(0xc0fecdabbeefcdab_u64)
);
TestPrimitive!(
test_u128,
u128,
vec![
0xabu8, 0xcd, 0xef, 0xbe, 0xab, 0xcd, 0xfe, 0xc0, 0xab, 0xcd, 0xef, 0xbe, 0xab, 0xcd,
0xfe, 0xc0
],
native_endian!(0xc0fecdabbeefcdabc0fecdabbeefcdab_u128)
);
TestPrimitive!(
test_usize,
usize,
vec![0xabu8, 0xcd, 0xef, 0xbe, 0xab, 0xcd, 0xfe, 0xc0],
if core::mem::size_of::<usize>() == 8 {
native_endian!(0xc0fecdabbeefcdab_usize)
} else {
native_endian!(0xbeefcdab_usize)
}
);
TestPrimitive!(test_i8, i8, vec![0xfbu8], -5);
TestPrimitive!(test_i16, i16, vec![0xfdu8, 0xfe], native_endian!(-259_i16));
TestPrimitive!(
test_i32,
i32,
vec![0x02u8, 0x3f, 0x01, 0xef],
native_endian!(-0x10fec0fe_i32)
);
TestPrimitive!(
test_i64,
i64,
vec![0x02u8, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef],
native_endian!(-0x10fec0fe10fec0fe_i64)
);
TestPrimitive!(
test_i128,
i128,
vec![
0x02u8, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef, 0x01, 0x3f,
0x01, 0xef
],
native_endian!(-0x10fec0fe10fec0fe10fec0fe10fec0fe_i128)
);
TestPrimitive!(
test_isize,
isize,
vec![0x02u8, 0x3f, 0x01, 0xef, 0x01, 0x3f, 0x01, 0xef],
if core::mem::size_of::<isize>() == 8 {
native_endian!(-0x10fec0fe10fec0fe_isize)
} else {
native_endian!(-0x10fec0fe_isize)
}
);
TestPrimitive!(
test_f32,
f32,
vec![0xa6u8, 0x9b, 0xc4, 0xbb],
native_endian!(-0.006_f32)
);
TestPrimitive!(
test_f64,
f64,
vec![0xfau8, 0x7e, 0x6a, 0xbc, 0x74, 0x93, 0x78, 0xbf],
native_endian!(-0.006_f64)
);
#[cfg(all(feature = "bits", feature = "descriptive-errors"))]
#[rstest(input, endian, bit_size, expected, expected_rest_bits, expected_rest_bytes,
case::normal([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Little, Some(32), 0xAABB_CCDD, bits![u8, Msb0;], &[]),
case::normal([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Big, Some(32), 0xDDCC_BBAA, bits![u8, Msb0;], &[]),
case::normal_bits_12_le([0b1001_0110, 0b1110_0000, 0xCC, 0xDD ].as_ref(), Endian::Little, Some(12), 0b1110_1001_0110, bits![u8, Msb0; 0, 0, 0, 0], &[0xcc, 0xdd]),
case::normal_bits_12_be([0b1001_0110, 0b1110_0000, 0xCC, 0xDD ].as_ref(), Endian::Big, Some(12), 0b1001_0110_1110, bits![u8, Msb0; 0, 0, 0, 0], &[0xcc, 0xdd]),
case::normal_bit_6([0b1001_0110].as_ref(), Endian::Little, Some(6), 0b1001_01, bits![u8, Msb0; 1, 0,], &[]),
#[should_panic(expected = "Incomplete(NeedSize { bits: 32 })")]
case::not_enough_data([].as_ref(), Endian::Little, Some(32), 0xFF, bits![u8, Msb0;], &[]),
#[should_panic(expected = "Incomplete(NeedSize { bits: 32 })")]
case::not_enough_data([0xAA, 0xBB].as_ref(), Endian::Little, Some(32), 0xFF, bits![u8, Msb0;], &[]),
#[should_panic(expected = "Parse(\"too much data: container of 32 bits cannot hold 64 bits\")")] // This will end up in ByteSize b/c 64 % 8 == 0
case::too_much_data([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD].as_ref(), Endian::Little, Some(64), 0xFF, bits![u8, Msb0;], &[]),
#[should_panic(expected = "Parse(\"too much data: container of 32 bits cannot hold 63 bits\")")] // This will end up staying BitSize
case::too_much_data([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD].as_ref(), Endian::Little, Some(63), 0xFF, bits![u8, Msb0;], &[]),
)]
fn test_bit_read(
input: &[u8],
endian: Endian,
bit_size: Option<usize>,
expected: u32,
expected_rest_bits: &BitSlice<u8, Msb0>,
expected_rest_bytes: &[u8],
) {
let mut cursor = std::io::Cursor::new(input);
let mut reader = Reader::new(&mut cursor);
let res_read = match bit_size {
Some(bit_size) => {
u32::from_reader_with_ctx(&mut reader, (endian, BitSize(bit_size))).unwrap()
}
None => u32::from_reader_with_ctx(&mut reader, endian).unwrap(),
};
assert_eq!(expected, res_read);
assert_eq!(
reader.rest(),
expected_rest_bits.iter().by_vals().collect::<Vec<bool>>()
);
let mut buf = vec![];
cursor.read_to_end(&mut buf).unwrap();
assert_eq!(expected_rest_bytes, buf);
}
#[cfg(feature = "descriptive-errors")]
#[rstest(input, endian, byte_size, expected, expected_rest_bytes,
case::normal_be([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Big, Some(4), 0xDDCC_BBAA, &[]),
case::normal_le([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Little, Some(4), 0xAABB_CCDD, &[]),
case::normal_be([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Big, Some(3), 0x00DDCC_BB, &[0xaa]),
case::normal_be([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Little, Some(3), 0x00BB_CCDD, &[0xaa]),
#[should_panic(expected = "Incomplete(NeedSize { bits: 32 })")]
case::not_enough_data([].as_ref(), Endian::Little, Some(4), 0xFF, &[]),
#[should_panic(expected = "Incomplete(NeedSize { bits: 32 })")]
case::not_enough_data([0xAA, 0xBB].as_ref(), Endian::Little, Some(4), 0xFF, &[]),
#[should_panic(expected = "Parse(\"too much data: container of 4 bytes cannot hold 8 bytes\")")]
case::too_much_data([0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD].as_ref(), Endian::Little, Some(8), 0xFF, &[]),
)]
fn test_byte_read(
input: &[u8],
endian: Endian,
byte_size: Option<usize>,
expected: u32,
expected_rest_bytes: &[u8],
) {
let mut cursor = std::io::Cursor::new(input);
let mut reader = Reader::new(&mut cursor);
let res_read = match byte_size {
Some(byte_size) => {
u32::from_reader_with_ctx(&mut reader, (endian, ByteSize(byte_size))).unwrap()
}
None => u32::from_reader_with_ctx(&mut reader, endian).unwrap(),
};
assert_eq!(expected, res_read);
let mut buf = vec![];
cursor.read_to_end(&mut buf).unwrap();
assert_eq!(expected_rest_bytes, buf);
}
#[cfg(all(feature = "bits", feature = "descriptive-errors"))]
#[rstest(input, endian, bit_size, expected, expected_leftover,
case::normal_le(0xDDCC_BBAA, Endian::Little, None, vec![0xAA, 0xBB, 0xCC, 0xDD], vec![]),
case::normal_be(0xDDCC_BBAA, Endian::Big, None, vec![0xDD, 0xCC, 0xBB, 0xAA], vec![]),
case::bit_size_be_smaller(0x03AB, Endian::Big, Some(10), vec![0b11_1010_10], vec![true, true]),
#[should_panic(expected = "InvalidParam(\"bit size is larger than input: 100 exceeds 32\")")]
case::bit_size_le_bigger(0x03AB, Endian::Little, Some(100), vec![0xAB, 0b11_000000], vec![true, true]),
#[should_panic(expected = "InvalidParam(\"bit size of input is larger than requested size: 10 exceeds 5\")")]
case::bit_size_larger(0x03AB, Endian::Little, Some(5), vec![], vec![]),
)]
fn test_bit_writer(
input: u32,
endian: Endian,
bit_size: Option<usize>,
expected: Vec<u8>,
expected_leftover: Vec<bool>,
) {
let mut writer = Writer::new(Cursor::new(vec![]));
match bit_size {
Some(bit_size) => input
.to_writer(&mut writer, (endian, BitSize(bit_size)))
.unwrap(),
None => input.to_writer(&mut writer, endian).unwrap(),
};
assert_eq!(expected_leftover, writer.rest());
assert_eq!(expected, writer.inner.into_inner());
}
#[cfg(feature = "descriptive-errors")]
#[rstest(input, endian, byte_size, expected,
case::normal_le(0xDDCC_BBAA, Endian::Little, None, vec![0xAA, 0xBB, 0xCC, 0xDD]),
case::normal_be(0xDDCC_BBAA, Endian::Big, None, vec![0xDD, 0xCC, 0xBB, 0xAA]),
case::byte_size_be_smaller(0x00FFABAA, Endian::Big, Some(2), vec![0xab, 0xaa]),
#[should_panic(expected = "InvalidParam(\"byte size is larger than input: 10 exceeds 4\")")]
case::byte_size_le_bigger(0x03AB, Endian::Little, Some(10), vec![0xAB, 0b11_000000]),
)]
fn test_byte_writer(input: u32, endian: Endian, byte_size: Option<usize>, expected: Vec<u8>) {
let mut writer = Writer::new(Cursor::new(vec![]));
match byte_size {
Some(byte_size) => input
.to_writer(&mut writer, (endian, ByteSize(byte_size)))
.unwrap(),
None => input.to_writer(&mut writer, endian).unwrap(),
};
assert_hex::assert_eq_hex!(expected, writer.inner.into_inner());
}
#[cfg(feature = "bits")]
#[rstest(input, endian, bit_size, expected, expected_write,
case::normal([0xDD, 0xCC, 0xBB, 0xAA].as_ref(), Endian::Little, Some(32), 0xAABB_CCDD, vec![0xDD, 0xCC, 0xBB, 0xAA]),
)]
fn test_bit_read_write(
input: &[u8],
endian: Endian,
bit_size: Option<usize>,
expected: u32,
expected_write: Vec<u8>,
) {
let mut cursor = std::io::Cursor::new(input);
let mut reader = Reader::new(&mut cursor);
let res_read = match bit_size {
Some(bit_size) => {
u32::from_reader_with_ctx(&mut reader, (endian, BitSize(bit_size))).unwrap()
}
None => u32::from_reader_with_ctx(&mut reader, endian).unwrap(),
};
assert_eq!(expected, res_read);
let mut writer = Writer::new(Cursor::new(vec![]));
match bit_size {
Some(bit_size) => res_read
.to_writer(&mut writer, (endian, BitSize(bit_size)))
.unwrap(),
None => res_read.to_writer(&mut writer, endian).unwrap(),
};
assert_hex::assert_eq_hex!(expected_write, writer.inner.into_inner());
}
#[cfg(feature = "bits")]
macro_rules! TestSignExtending {
($test_name:ident, $typ:ty) => {
#[test]
fn $test_name() {
let slice = [0b10101_000].as_slice();
let mut cursor = std::io::Cursor::new(slice);
let mut reader = Reader::new(&mut cursor);
let res_read =
<$typ>::from_reader_with_ctx(&mut reader, (Endian::Little, BitSize(5)))
.unwrap();
assert_eq!(-11, res_read);
}
};
}
#[cfg(feature = "bits")]
TestSignExtending!(test_sign_extend_i8, i8);
#[cfg(feature = "bits")]
TestSignExtending!(test_sign_extend_i16, i16);
#[cfg(feature = "bits")]
TestSignExtending!(test_sign_extend_i32, i32);
#[cfg(feature = "bits")]
TestSignExtending!(test_sign_extend_i64, i64);
#[cfg(feature = "bits")]
TestSignExtending!(test_sign_extend_i128, i128);
#[cfg(feature = "bits")]
TestSignExtending!(test_sign_extend_isize, isize);
#[cfg(feature = "bits")]
macro_rules! TestSignExtendingPanic {
($test_name:ident, $typ:ty, $size:expr) => {
#[test]
fn $test_name() {
let slice = [0b10101_000].as_slice();
let mut cursor = std::io::Cursor::new(slice);
let mut reader = Reader::new(&mut cursor);
let res_read =
<$typ>::from_reader_with_ctx(&mut reader, (Endian::Little, BitSize($size + 1)));
assert_eq!(
deku_error!(
DekuError::Parse,
"too much data",
"container of {} bits cannot hold {} bits",
$size,
$size + 1
),
res_read.err().unwrap()
);
}
};
}
#[cfg(feature = "bits")]
TestSignExtendingPanic!(test_sign_extend_i8_panic, i8, 8);
#[cfg(feature = "bits")]
TestSignExtendingPanic!(test_sign_extend_i16_panic, i16, 16);
#[cfg(feature = "bits")]
TestSignExtendingPanic!(test_sign_extend_i32_panic, i32, 32);
#[cfg(feature = "bits")]
TestSignExtendingPanic!(test_sign_extend_i64_panic, i64, 64);
#[cfg(feature = "bits")]
TestSignExtendingPanic!(test_sign_extend_i128_panic, i128, 128);
}