use powerio_core::{DiagnosticInfo, ErrorCategory};
use thiserror::Error;
use crate::diagnostics::codes;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("io error reading {path}: {source}")]
Io {
path: String,
#[source]
source: std::io::Error,
},
#[error("malformed {format} JSON: {message}")]
Json {
format: &'static str,
message: String,
},
#[error("{format} read error: {message}")]
FormatRead {
format: &'static str,
message: String,
},
#[error("unknown distribution format `{0}` (expected dss, bmopf, or pmd)")]
UnknownFormat(String),
#[error("neutral Kron reduction failed: {message}")]
KronReduction { message: String },
#[error("LinDist3Flow preparation failed: {message}")]
LinDist3FlowPreparation { message: String },
}
impl Error {
#[must_use]
pub fn code(&self) -> &'static DiagnosticInfo {
match self {
Error::Io { .. } => &codes::READ_DIST_IO_FAILED,
Error::Json { .. } => &codes::PARSE_DIST_MALFORMED,
Error::FormatRead { .. } => &codes::PARSE_DIST_SOURCE_MALFORMED,
Error::UnknownFormat(_) => &codes::REQUEST_DIST_FORMAT_UNKNOWN,
Error::KronReduction { .. } => &codes::TRANSFORM_DIST_KRON_REDUCTION_FAILED,
Error::LinDist3FlowPreparation { .. } => {
&codes::TRANSFORM_DIST_LINDIST3FLOW_PREPARATION_FAILED
}
}
}
#[must_use]
pub fn category(&self) -> ErrorCategory {
match self {
Error::Io { .. } => ErrorCategory::Io,
Error::Json { .. } | Error::FormatRead { .. } => ErrorCategory::Parse,
Error::UnknownFormat(_) => ErrorCategory::Request,
Error::KronReduction { .. } | Error::LinDist3FlowPreparation { .. } => {
ErrorCategory::Data
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_error_code_publishes_the_category_the_variant_reports() {
let every = [
Error::Io {
path: "case.dss".into(),
source: std::io::Error::from(std::io::ErrorKind::NotFound),
},
Error::Json {
format: "BMOPF",
message: "top level is not an object".into(),
},
Error::FormatRead {
format: "case text",
message: "not valid UTF-8".into(),
},
Error::UnknownFormat("xyz".into()),
Error::KronReduction {
message: "ambiguous neutral".into(),
},
Error::LinDist3FlowPreparation {
message: "unsupported transformer".into(),
},
];
for error in &every {
assert_eq!(
error.code().category,
Some(error.category()),
"{}",
error.code().code
);
}
}
}