binread/
error.rs

1//! Error types and internal error handling functions
2use super::*;
3
4/// An error while parsing a BinRead type
5#[non_exhaustive]
6pub enum Error {
7    /// The magic value did not match the provided one
8    BadMagic {
9        // Position in number of bytes from the start of the reader
10        pos: u64,
11        // The value found. Use [`Any::downcast_ref`](core::any::Any::downcast_ref) to access
12        found: Box<dyn Any + Sync + Send>,
13    },
14    /// The condition of an assertion without a custom type failed
15    AssertFail { pos: u64, message: String },
16    /// An error that occured while reading from, or seeking within, the reader
17    Io(io::Error),
18    /// A custom error, most often given from the second value passed into an [`assert`](attribute#Assert)
19    Custom {
20        pos: u64,
21        err: Box<dyn Any + Sync + Send>,
22    },
23    /// No variant in the enum was successful in parsing the data
24    NoVariantMatch { pos: u64 },
25    EnumErrors {
26        pos: u64,
27        variant_errors: Vec<(/*variant name*/ &'static str, Error)>,
28    },
29}
30
31impl Error {
32    /// Gets a custom error of type T from the Error. Returns `None` if the error type is not
33    /// custom or if the contained error is not of the desired type.
34    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
82/// Read a value then check if it is the expected value
83pub 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/// Assert a condition is true and if not optionally apply a function to generate the error
107#[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}