1use powerio_core::{DiagnosticInfo, ErrorCategory};
2use thiserror::Error;
3
4use crate::diagnostics::codes;
5
6pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Debug, Error)]
9#[non_exhaustive]
10pub enum Error {
11 #[error("io error reading {path}: {source}")]
12 Io {
13 path: String,
14 #[source]
15 source: std::io::Error,
16 },
17
18 #[error("malformed {format} JSON: {message}")]
19 Json {
20 format: &'static str,
21 message: String,
22 },
23
24 #[error("{format} read error: {message}")]
25 FormatRead {
26 format: &'static str,
27 message: String,
28 },
29
30 #[error("unknown distribution format `{0}` (expected dss, bmopf, or pmd)")]
31 UnknownFormat(String),
32
33 #[error("neutral Kron reduction failed: {message}")]
34 KronReduction { message: String },
35}
36
37impl Error {
38 #[must_use]
41 pub fn code(&self) -> &'static DiagnosticInfo {
42 match self {
43 Error::Io { .. } => &codes::READ_DIST_IO_FAILED,
44 Error::Json { .. } => &codes::PARSE_DIST_MALFORMED,
45 Error::FormatRead { .. } => &codes::PARSE_DIST_SOURCE_MALFORMED,
46 Error::UnknownFormat(_) => &codes::REQUEST_DIST_FORMAT_UNKNOWN,
47 Error::KronReduction { .. } => &codes::TRANSFORM_DIST_KRON_REDUCTION_FAILED,
48 }
49 }
50
51 #[must_use]
53 pub fn category(&self) -> ErrorCategory {
54 match self {
55 Error::Io { .. } => ErrorCategory::Io,
56 Error::Json { .. } | Error::FormatRead { .. } => ErrorCategory::Parse,
57 Error::UnknownFormat(_) => ErrorCategory::Request,
58 Error::KronReduction { .. } => ErrorCategory::Data,
59 }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn every_error_code_publishes_the_category_the_variant_reports() {
69 let every = [
70 Error::Io {
71 path: "case.dss".into(),
72 source: std::io::Error::from(std::io::ErrorKind::NotFound),
73 },
74 Error::Json {
75 format: "BMOPF",
76 message: "top level is not an object".into(),
77 },
78 Error::FormatRead {
79 format: "case text",
80 message: "not valid UTF-8".into(),
81 },
82 Error::UnknownFormat("xyz".into()),
83 Error::KronReduction {
84 message: "ambiguous neutral".into(),
85 },
86 ];
87 for error in &every {
88 assert_eq!(
89 error.code().category,
90 Some(error.category()),
91 "{}",
92 error.code().code
93 );
94 }
95 }
96}