Skip to main content

image_rider/
error.rs

1//! Error results that can occur working with images
2#![warn(missing_docs)]
3#![warn(unsafe_code)]
4use std::{
5    fmt::{Debug, Display, Formatter, Result},
6    io,
7};
8
9/// An error that can occur when processing an image, ROM or other
10/// file.
11pub struct Error {
12    kind: ErrorKind,
13    // reqwest (0.12.12) has a fairly good Error implementation
14    // showing how to do source with boxes.
15    // source: String,
16}
17
18impl Debug for Error {
19    fn fmt(&self, f: &mut Formatter) -> Result {
20        write!(f, "{}", self.kind)
21    }
22}
23
24impl Display for Error {
25    fn fmt(&self, f: &mut Formatter) -> Result {
26        write!(f, "{}", self.kind)
27    }
28}
29
30impl std::error::Error for Error {
31    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
32        match self.kind {
33            ErrorKind::IO(ref io) => Some(io),
34            _ => None,
35        }
36    }
37}
38
39impl Error {
40    /// Create a new Error with a given ErrorKind variant
41    pub fn new(kind: ErrorKind) -> Error {
42        Error { kind }
43    }
44}
45
46impl From<nom::Err<nom::error::Error<&[u8]>>> for Error {
47    fn from(e: nom::Err<nom::error::Error<&[u8]>>) -> Self {
48        Error::new(ErrorKind::new(&e.to_string()))
49    }
50}
51
52// impl From<nom::Err<nom::error::ParseError<&[u8]>>> for Error {
53//     fn from(e: nom::Err<nom::error::Error<&[u8]>>) -> Self {
54//         Error::new(ErrorKind::new(&e.to_string()))
55//     }
56// }
57
58impl<'a> nom::error::ParseError<&'a [u8]> for Error {
59    fn from_error_kind(_input: &'a [u8], kind: nom::error::ErrorKind) -> Self {
60        Error::new(ErrorKind::new(kind.description()))
61    }
62
63    fn append(_input: &'a [u8], _kind: nom::error::ErrorKind, other: Self) -> Self {
64        other
65    }
66}
67
68impl From<std::io::Error> for Error {
69    fn from(e: std::io::Error) -> Self {
70        Error::new(ErrorKind::IO(e))
71    }
72}
73
74/// The kinds of errors that can occur when processing an image, ROM
75/// or other file.
76#[derive(Debug)]
77pub enum ErrorKind {
78    /// Generic error type
79    Message(String),
80
81    /// An error that occurs when dealing with invalid or unexpected
82    /// data.
83    Invalid(InvalidErrorKind),
84
85    /// The file was in a format that is unsupported or has
86    /// unsupported features.
87    Unimplemented(String),
88
89    /// The data requested was not found in the image.  This can occur
90    /// when attempting to extract a specific file from a file, or
91    /// when attempting to extract a certain sector or other item.
92    NotFound(String),
93
94    /// An IO based error
95    // goblin (0.8.2) has an implementation using Error enums to store
96    // the source error
97    IO(io::Error),
98}
99
100impl Display for ErrorKind {
101    fn fmt(&self, f: &mut Formatter) -> Result {
102        match self {
103            ErrorKind::Message(message) => write!(f, "An error occurred: {}", message),
104            ErrorKind::Invalid(e) => write!(f, "{}", e),
105            ErrorKind::Unimplemented(message) => {
106                write!(f, "Unimplemented feature: {}", message)
107            }
108            ErrorKind::NotFound(message) => {
109                write!(f, "Data not found: {}", message)
110            }
111            ErrorKind::IO(io) => {
112                write!(f, "IO error: {}", io)
113            }
114        }
115    }
116}
117
118impl ErrorKind {
119    /// Return a new generic ErrorKind::Message with a given string message.
120    pub fn new(message: &str) -> ErrorKind {
121        ErrorKind::Message(message.to_string())
122    }
123}
124
125/// An InvalidErrorKind is returned when the data is invalid.
126#[derive(Debug, Eq, PartialEq)]
127pub enum InvalidErrorKind {
128    /// The data was invalid
129    Invalid(String),
130    /// The data contains an invalid checksum
131    Checksum,
132}
133
134impl Display for InvalidErrorKind {
135    fn fmt(&self, f: &mut Formatter) -> Result {
136        match self {
137            InvalidErrorKind::Invalid(message) => write!(f, "Image is invalid: {}", message),
138            InvalidErrorKind::Checksum => write!(f, "Image has an invalid checksum"),
139        }
140    }
141}
142
143/// Test the error code
144#[allow(unused_imports)]
145#[cfg(test)]
146pub mod tests {
147    use crate::error::ErrorKind;
148
149    /// Test that creating an ErrorKind with new works
150    #[test]
151    pub fn error_kind_new_works() {
152        let ek1 = ErrorKind::new("Test1");
153        let ek2 = ErrorKind::new("Test1");
154
155        matches!(ek1, ErrorKind::Message(x) if x == "Test1");
156        matches!(ek2, ErrorKind::Message(x) if x == "Test1");
157    }
158
159    /// Test that creating an ErrorKind::NotFound works
160    #[test]
161    pub fn error_kind_not_found_works() {
162        let ek = ErrorKind::NotFound(String::from("Test1"));
163        matches!(ek, ErrorKind::NotFound(x) if x == "Test1");
164    }
165}