use crate::{
io::{self, Read, Seek},
BinRead, BinResult, Endian, Error, NamedArgs,
};
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};
use core::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16,
NonZeroU32, NonZeroU64, NonZeroU8,
};
macro_rules! binread_impl {
($($type_name:ty),*$(,)?) => {
$(
impl BinRead for $type_name {
type Args<'a> = ();
fn read_options<R: Read + Seek>(reader: &mut R, endian: Endian, (): Self::Args<'_>) -> BinResult<Self> {
let mut val = [0; core::mem::size_of::<$type_name>()];
let pos = reader.stream_position()?;
reader.read_exact(&mut val).or_else(crate::__private::restore_position(reader, pos))?;
Ok(match endian {
Endian::Big => {
<$type_name>::from_be_bytes(val)
}
Endian::Little => {
<$type_name>::from_le_bytes(val)
}
})
}
}
)*
}
}
binread_impl!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
fn unexpected_zero_num() -> Error {
Error::Io(io::Error::new(
io::ErrorKind::InvalidData,
"unexpected zero found",
))
}
macro_rules! binread_nonzero_impl {
($($Ty:ty, $Int:ty),* $(,)?) => {
$(
impl BinRead for $Ty {
type Args<'a> = ();
fn read_options<R: Read + Seek>(
reader: &mut R,
endian: Endian,
(): Self::Args<'_>,
) -> BinResult<Self> {
match <$Ty>::new(<$Int>::read_options(reader, endian, ())?) {
Some(x) => Ok(x),
None => Err(unexpected_zero_num()),
}
}
}
)+
}
}
binread_nonzero_impl! {
NonZeroU8, u8, NonZeroU16, u16, NonZeroU32, u32, NonZeroU64, u64, NonZeroU128, u128,
NonZeroI8, i8, NonZeroI16, i16, NonZeroI32, i32, NonZeroI64, i64, NonZeroI128, i128,
}
#[derive(NamedArgs, Clone)]
pub struct VecArgs<Inner: Clone> {
pub count: usize,
#[named_args(try_optional)]
pub inner: Inner,
}
impl<B> BinRead for Vec<B>
where
B: BinRead + 'static,
for<'a> B::Args<'a>: Clone,
{
type Args<'a> = VecArgs<B::Args<'a>>;
fn read_options<R: Read + Seek>(
reader: &mut R,
endian: Endian,
args: Self::Args<'_>,
) -> BinResult<Self> {
crate::helpers::count_with(args.count, B::read_options)(reader, endian, args.inner)
}
}
impl<B, const N: usize> BinRead for [B; N]
where
B: BinRead,
for<'a> B::Args<'a>: Clone,
{
type Args<'a> = B::Args<'a>;
fn read_options<R: Read + Seek>(
reader: &mut R,
endian: Endian,
args: Self::Args<'_>,
) -> BinResult<Self> {
array_init::try_array_init(|_| BinRead::read_options(reader, endian, args.clone()))
}
}
macro_rules! binread_tuple_impl {
($type1:ident $(, $types:ident)*) => {
#[allow(non_camel_case_types)]
impl<Args: Clone, $type1: for<'a> BinRead<Args<'a> = Args>, $($types: for<'a> BinRead<Args<'a> = Args>),*> BinRead for ($type1, $($types),*) {
type Args<'a> = Args;
fn read_options<R: Read + Seek>(reader: &mut R, endian: Endian, args: Self::Args<'_>) -> BinResult<Self> {
Ok((
BinRead::read_options(reader, endian, args.clone())?,
$(
<$types>::read_options(reader, endian, args.clone())?
),*
))
}
}
binread_tuple_impl!($($types),*);
};
() => {};
}
binread_tuple_impl!(
b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21,
b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32
);
impl BinRead for () {
type Args<'a> = ();
fn read_options<R: Read + Seek>(_: &mut R, _: Endian, (): Self::Args<'_>) -> BinResult<Self> {
Ok(())
}
}
impl<T: BinRead> BinRead for Box<T> {
type Args<'a> = T::Args<'a>;
fn read_options<R: Read + Seek>(
reader: &mut R,
endian: Endian,
args: Self::Args<'_>,
) -> BinResult<Self> {
Ok(Box::new(T::read_options(reader, endian, args)?))
}
}
impl<T: BinRead> BinRead for Option<T> {
type Args<'a> = T::Args<'a>;
fn read_options<R: Read + Seek>(
reader: &mut R,
endian: Endian,
args: Self::Args<'_>,
) -> BinResult<Self> {
Ok(Some(T::read_options(reader, endian, args)?))
}
}
impl<T> BinRead for core::marker::PhantomData<T> {
type Args<'a> = ();
fn read_options<R: Read + Seek>(_: &mut R, _: Endian, (): Self::Args<'_>) -> BinResult<Self> {
Ok(core::marker::PhantomData)
}
}