use super::*;
#[non_exhaustive]
pub enum Error {
BadMagic {
pos: u64,
found: Box<dyn Any + Sync + Send>,
},
AssertFail { pos: u64, message: String },
Io(io::Error),
Custom {
pos: u64,
err: Box<dyn Any + Sync + Send>,
},
NoVariantMatch { pos: u64 },
EnumErrors {
pos: u64,
variant_errors: Vec<(&'static str, Error)>,
},
}
impl Error {
pub fn custom_err<T: Any>(&self) -> Option<&T> {
if let Error::Custom { err, .. } = self {
err.downcast_ref()
} else {
None
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::Io(err)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
use core::fmt;
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BadMagic { pos, .. } => write!(f, "BadMagic {{ pos: 0x{:X} }}", pos),
Self::AssertFail { pos, message } => {
write!(f, "AssertFail at 0x{:X}: \"{}\"", pos, message)
}
Self::Io(err) => write!(f, "Io({:?})", err),
Self::Custom { pos, err } => write!(f, "Custom {{ pos: 0x{:X}, err: {:?} }}", pos, err),
Self::NoVariantMatch { pos } => write!(f, "NoVariantMatch {{ pos: 0x{:X} }}", pos),
Self::EnumErrors {
pos,
variant_errors,
} => write!(
f,
"EnumErrors {{ pos: 0x{:X}, variant_errors: {:?} }}",
pos, variant_errors
),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
pub fn magic<R, B>(reader: &mut R, expected: B, options: &ReadOptions) -> BinResult<()>
where
B: BinRead<Args = ()> + PartialEq + Sync + Send + 'static,
R: io::Read + io::Seek,
{
let pos = reader.stream_pos()?;
#[cfg(feature = "debug_template")]
let options = {
let mut options = *options;
options.variable_name = Some("magic");
options
};
let val = B::read_options(reader, &options, ())?;
if val == expected {
Ok(())
} else {
Err(Error::BadMagic {
pos,
found: Box::new(val) as _,
})
}
}
#[deprecated]
pub fn assert<R, E, A>(reader: &mut R, test: bool, message: &str, error: Option<E>) -> BinResult<()>
where
R: io::Read + io::Seek,
A: core::fmt::Debug + Sync + Send + 'static,
E: Fn() -> A,
{
let pos = reader.stream_pos()?;
if test {
Ok(())
} else {
error
.map(|err| {
Err(Error::Custom {
pos,
err: Box::new(err()),
})
})
.unwrap_or_else(|| {
Err(Error::AssertFail {
pos,
message: message.into(),
})
})
}
}
pub fn read_options_then_after_parse<Args, T, R>(
reader: &mut R,
ro: &ReadOptions,
args: T::Args,
) -> BinResult<T>
where
Args: Copy + 'static,
T: BinRead<Args = Args>,
R: Read + Seek,
{
let mut val = T::read_options(reader, ro, args)?;
val.after_parse(reader, ro, args)?;
Ok(val)
}