1use super::*;
3
4#[non_exhaustive]
6pub enum Error {
7 BadMagic {
9 pos: u64,
11 found: Box<dyn Any + Sync + Send>,
13 },
14 AssertFail { pos: u64, message: String },
16 Io(io::Error),
18 Custom {
20 pos: u64,
21 err: Box<dyn Any + Sync + Send>,
22 },
23 NoVariantMatch { pos: u64 },
25 EnumErrors {
26 pos: u64,
27 variant_errors: Vec<(&'static str, Error)>,
28 },
29}
30
31impl Error {
32 pub fn custom_err<T: Any>(&self) -> Option<&T> {
35 if let Error::Custom { err, .. } = self {
36 err.downcast_ref()
37 } else {
38 None
39 }
40 }
41}
42
43impl From<io::Error> for Error {
44 fn from(err: io::Error) -> Self {
45 Self::Io(err)
46 }
47}
48
49#[cfg(feature = "std")]
50impl std::error::Error for Error {}
51
52use core::fmt;
53
54impl fmt::Debug for Error {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 match self {
57 Self::BadMagic { pos, .. } => write!(f, "BadMagic {{ pos: 0x{:X} }}", pos),
58 Self::AssertFail { pos, message } => {
59 write!(f, "AssertFail at 0x{:X}: \"{}\"", pos, message)
60 }
61 Self::Io(err) => write!(f, "Io({:?})", err),
62 Self::Custom { pos, err } => write!(f, "Custom {{ pos: 0x{:X}, err: {:?} }}", pos, err),
63 Self::NoVariantMatch { pos } => write!(f, "NoVariantMatch {{ pos: 0x{:X} }}", pos),
64 Self::EnumErrors {
65 pos,
66 variant_errors,
67 } => write!(
68 f,
69 "EnumErrors {{ pos: 0x{:X}, variant_errors: {:?} }}",
70 pos, variant_errors
71 ),
72 }
73 }
74}
75
76impl fmt::Display for Error {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 fmt::Debug::fmt(self, f)
79 }
80}
81
82pub fn magic<R, B>(reader: &mut R, expected: B, options: &ReadOptions) -> BinResult<()>
84where
85 B: BinRead<Args = ()> + PartialEq + Sync + Send + 'static,
86 R: io::Read + io::Seek,
87{
88 let pos = reader.stream_pos()?;
89 #[cfg(feature = "debug_template")]
90 let options = {
91 let mut options = *options;
92 options.variable_name = Some("magic");
93 options
94 };
95 let val = B::read_options(reader, &options, ())?;
96 if val == expected {
97 Ok(())
98 } else {
99 Err(Error::BadMagic {
100 pos,
101 found: Box::new(val) as _,
102 })
103 }
104}
105
106#[deprecated]
108pub fn assert<R, E, A>(reader: &mut R, test: bool, message: &str, error: Option<E>) -> BinResult<()>
109where
110 R: io::Read + io::Seek,
111 A: core::fmt::Debug + Sync + Send + 'static,
112 E: Fn() -> A,
113{
114 let pos = reader.stream_pos()?;
115 if test {
116 Ok(())
117 } else {
118 error
119 .map(|err| {
120 Err(Error::Custom {
121 pos,
122 err: Box::new(err()),
123 })
124 })
125 .unwrap_or_else(|| {
126 Err(Error::AssertFail {
127 pos,
128 message: message.into(),
129 })
130 })
131 }
132}
133
134pub fn read_options_then_after_parse<Args, T, R>(
135 reader: &mut R,
136 ro: &ReadOptions,
137 args: T::Args,
138) -> BinResult<T>
139where
140 Args: Copy + 'static,
141 T: BinRead<Args = Args>,
142 R: Read + Seek,
143{
144 let mut val = T::read_options(reader, ro, args)?;
145 val.after_parse(reader, ro, args)?;
146 Ok(val)
147}