1use std::fmt;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct SparError {
9 message: String,
10}
11
12impl SparError {
13 pub fn new(message: impl Into<String>) -> Self {
14 Self {
15 message: message.into(),
16 }
17 }
18
19 pub fn message(&self) -> &str {
20 &self.message
21 }
22
23 pub fn last_line(&self) -> &str {
26 self.message.lines().next_back().unwrap_or(&self.message)
27 }
28
29 pub fn first_line(&self) -> &str {
31 self.message.lines().next().unwrap_or(&self.message)
32 }
33}
34
35impl fmt::Display for SparError {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.write_str(&self.message)
38 }
39}
40
41impl std::error::Error for SparError {}
42
43impl From<std::io::Error> for SparError {
44 fn from(e: std::io::Error) -> Self {
45 SparError::new(e.to_string())
46 }
47}
48
49impl From<serde_json::Error> for SparError {
50 fn from(e: serde_json::Error) -> Self {
51 SparError::new(format!("invalid JSON: {e}"))
52 }
53}
54
55impl From<toml::de::Error> for SparError {
56 fn from(e: toml::de::Error) -> Self {
57 SparError::new(format!("invalid TOML: {e}"))
58 }
59}
60
61pub type Result<T> = std::result::Result<T, SparError>;
62
63#[macro_export]
65macro_rules! spar_err {
66 ($($arg:tt)*) => { $crate::error::SparError::new(format!($($arg)*)) };
67}
68
69#[macro_export]
71macro_rules! bail {
72 ($($arg:tt)*) => { return Err($crate::spar_err!($($arg)*)) };
73}