use std::{io, path::PathBuf};
pub type RoutingResult<T> = Result<T, RoutingError>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum RoutingError {
#[error("failed to read rule set file `{path}`: {source}")]
RuleSetRead {
path: PathBuf,
#[source]
source: io::Error,
},
#[error("invalid rule set TOML in `{path}`{canonical_display}: {source}", canonical_display = match canonical {
Some(p) => format!(" ({})", p.display()),
None => String::new(),
})]
RuleSetParse {
path: PathBuf,
canonical: Option<PathBuf>,
#[source]
source: Box<toml::de::Error>,
},
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RoutingErrorKind {
RuleSetRead,
RuleSetParse,
}
impl RoutingError {
pub fn kind(&self) -> RoutingErrorKind {
match self {
RoutingError::RuleSetRead { .. } => RoutingErrorKind::RuleSetRead,
RoutingError::RuleSetParse { .. } => RoutingErrorKind::RuleSetParse,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error as _;
fn a_toml_parse_error() -> toml::de::Error {
toml::from_str::<toml::Value>("not valid toml =====")
.expect_err("deliberately malformed TOML must fail to parse")
}
#[test]
fn rule_set_parse_display_matches_pre_boxing_format() {
let source = a_toml_parse_error();
let expected_source_display = source.to_string();
let err = RoutingError::RuleSetParse {
path: PathBuf::from("rules.toml"),
canonical: None,
source: Box::new(source),
};
assert_eq!(
err.to_string(),
format!("invalid rule set TOML in `rules.toml`: {expected_source_display}")
);
}
#[test]
fn rule_set_parse_source_reaches_the_boxed_toml_error() {
let source = a_toml_parse_error();
let source_display = source.to_string();
let err = RoutingError::RuleSetParse {
path: PathBuf::from("rules.toml"),
canonical: None,
source: Box::new(source),
};
let reached = err.source().expect("RuleSetParse always carries a source");
assert_eq!(reached.to_string(), source_display);
}
#[test]
fn routing_error_kind_matches_every_variant() {
assert_eq!(
RoutingError::RuleSetRead {
path: PathBuf::from("x"),
source: io::Error::other("x"),
}
.kind(),
RoutingErrorKind::RuleSetRead
);
assert_eq!(
RoutingError::RuleSetParse {
path: PathBuf::from("x"),
canonical: None,
source: Box::new(a_toml_parse_error()),
}
.kind(),
RoutingErrorKind::RuleSetParse
);
}
}