mutexpect/
error.rs

1use std::fmt;
2use std::path::{Path, PathBuf};
3
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7#[error("Expected {expected} {location} but observed: {observed}")]
8pub struct ParseError {
9    expected: &'static str,
10    observed: String,
11    location: Location,
12}
13
14#[derive(Debug)]
15pub enum Location {
16    Unknown,
17    File { path: PathBuf, line: usize },
18    Item { type_: &'static str, index: usize },
19}
20
21impl fmt::Display for Location {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            Location::Unknown => write!(f, "at unknown location"),
25            Location::File { path, line } => {
26                write!(f, "in file {} on line {}", path.as_path().display(), line)
27            }
28            Location::Item { type_, index } => {
29                write!(f, "for item of type {} at index {}", type_, index)
30            }
31        }
32    }
33}
34
35impl ParseError {
36    pub fn somewhere(expected: &'static str, observed: String) -> Self {
37        Self {
38            expected,
39            observed,
40            location: Location::Unknown,
41        }
42    }
43
44    pub fn file(path: PathBuf, line: usize, expected: &'static str, observed: String) -> Self {
45        let location = Location::File { path, line };
46        Self {
47            observed,
48            expected,
49            location,
50        }
51    }
52
53    pub fn item(
54        type_: &'static str,
55        index: usize,
56        expected: &'static str,
57        observed: String,
58    ) -> Self {
59        let location = Location::Item { type_, index };
60        Self {
61            observed,
62            expected,
63            location,
64        }
65    }
66}
67
68#[derive(Debug, Error)]
69pub struct FileError {
70    path: Option<PathBuf>,
71    #[source]
72    source: FileErrorSource,
73}
74
75impl FileError {
76    pub fn io<P: AsRef<Path>>(path: Option<P>, error: std::io::Error) -> Self {
77        let path = match path {
78            Some(p) => Some(p.as_ref().to_path_buf()),
79            None => None,
80        };
81        Self {
82            path,
83            source: error.into(),
84        }
85    }
86
87    pub fn parse<P: AsRef<Path>>(path: Option<P>, error: ParseError) -> Self {
88        let path = match path {
89            Some(p) => Some(p.as_ref().to_path_buf()),
90            None => None,
91        };
92        Self {
93            path,
94            source: error.into(),
95        }
96    }
97}
98
99impl fmt::Display for FileError {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match &self.path {
102            Some(path) => write!(f, "Failed to work with file {}", path.display()),
103            None => write!(f, "Failed to work fith anonymous file"),
104        }
105    }
106}
107
108#[derive(Debug, Error)]
109pub enum FileErrorSource {
110    #[error("Failed to parse file")]
111    Parse {
112        #[from]
113        source: ParseError,
114    },
115    #[error("Failed to read/write to file")]
116    IO {
117        #[from]
118        source: std::io::Error,
119    },
120}
121
122#[derive(Debug, Error)]
123pub struct SequenceError {
124    sequence_name: String,
125    message: &'static str,
126    #[source]
127    source: Option<Box<dyn std::error::Error>>,
128}
129
130impl SequenceError {
131    pub fn new(
132        sequence_name: String,
133        message: &'static str,
134        source: Option<Box<dyn std::error::Error>>,
135    ) -> Self {
136        Self {
137            sequence_name,
138            message,
139            source,
140        }
141    }
142}
143
144impl fmt::Display for SequenceError {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        write!(
147            f,
148            "Error in Sequence {}: {}",
149            self.sequence_name, self.message
150        )
151    }
152}
153
154/// Catch-all error for top-level API
155#[derive(Debug, Error)]
156pub enum MutexpectError {
157    #[error(transparent)]
158    ParseError(#[from] ParseError),
159    #[error(transparent)]
160    FileError(#[from] FileError),
161    #[error(transparent)]
162    SequenceError(#[from] SequenceError),
163}