1use core::fmt;
7
8pub type Result<T> = core::result::Result<T, Error>;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ErrorClass {
14 Io,
16 Usage,
18 InvalidContainer,
20 UnsupportedVersion,
22 UnsupportedFeature,
24 IntegrityMismatch,
26 ResourceLimit,
28 InvalidGraph,
30 InvalidModel,
32 EntropyDecode,
34 InvalidPdfStructure,
36 CodecReplay,
38 MissingExternalObject,
40 CoverageViolation,
42 ReconstructionMismatch,
44 Cancelled,
46 InvalidZipStructure,
50 InvalidXmlStructure,
53 InvalidPackageStructure,
57 InvalidJsonStructure,
61 InvalidYamlStructure,
65 InternalInvariant,
67}
68
69impl ErrorClass {
70 pub const fn exit_code(self) -> i32 {
72 match self {
73 ErrorClass::Io => 3,
74 ErrorClass::Usage => 2,
75 ErrorClass::InvalidContainer => 4,
76 ErrorClass::UnsupportedVersion => 5,
77 ErrorClass::UnsupportedFeature => 6,
78 ErrorClass::IntegrityMismatch => 7,
79 ErrorClass::ResourceLimit => 8,
80 ErrorClass::InvalidGraph => 9,
81 ErrorClass::InvalidModel => 10,
82 ErrorClass::EntropyDecode => 11,
83 ErrorClass::InvalidPdfStructure => 12,
84 ErrorClass::CodecReplay => 13,
85 ErrorClass::MissingExternalObject => 14,
86 ErrorClass::CoverageViolation => 15,
87 ErrorClass::ReconstructionMismatch => 16,
88 ErrorClass::Cancelled => 17,
89 ErrorClass::InvalidZipStructure => 18,
90 ErrorClass::InvalidXmlStructure => 19,
91 ErrorClass::InvalidPackageStructure => 20,
92 ErrorClass::InvalidJsonStructure => 21,
93 ErrorClass::InvalidYamlStructure => 22,
94 ErrorClass::InternalInvariant => 70,
95 }
96 }
97
98 pub const fn as_str(self) -> &'static str {
100 match self {
101 ErrorClass::Io => "Io",
102 ErrorClass::Usage => "Usage",
103 ErrorClass::InvalidContainer => "InvalidContainer",
104 ErrorClass::UnsupportedVersion => "UnsupportedVersion",
105 ErrorClass::UnsupportedFeature => "UnsupportedFeature",
106 ErrorClass::IntegrityMismatch => "IntegrityMismatch",
107 ErrorClass::ResourceLimit => "ResourceLimit",
108 ErrorClass::InvalidGraph => "InvalidGraph",
109 ErrorClass::InvalidModel => "InvalidModel",
110 ErrorClass::EntropyDecode => "EntropyDecode",
111 ErrorClass::InvalidPdfStructure => "InvalidPdfStructure",
112 ErrorClass::CodecReplay => "CodecReplay",
113 ErrorClass::MissingExternalObject => "MissingExternalObject",
114 ErrorClass::CoverageViolation => "CoverageViolation",
115 ErrorClass::ReconstructionMismatch => "ReconstructionMismatch",
116 ErrorClass::Cancelled => "Cancelled",
117 ErrorClass::InvalidZipStructure => "InvalidZipStructure",
118 ErrorClass::InvalidXmlStructure => "InvalidXmlStructure",
119 ErrorClass::InvalidPackageStructure => "InvalidPackageStructure",
120 ErrorClass::InvalidJsonStructure => "InvalidJsonStructure",
121 ErrorClass::InvalidYamlStructure => "InvalidYamlStructure",
122 ErrorClass::InternalInvariant => "InternalInvariant",
123 }
124 }
125}
126
127#[derive(Debug, Clone)]
129pub struct Error {
130 class: ErrorClass,
131 message: String,
132}
133
134impl Error {
135 pub fn new(class: ErrorClass, message: impl Into<String>) -> Self {
137 Error {
138 class,
139 message: message.into(),
140 }
141 }
142
143 pub fn class(&self) -> ErrorClass {
145 self.class
146 }
147
148 pub fn exit_code(&self) -> i32 {
150 self.class.exit_code()
151 }
152
153 pub fn message(&self) -> &str {
155 &self.message
156 }
157}
158
159impl fmt::Display for Error {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 write!(f, "{}: {}", self.class.as_str(), self.message)
162 }
163}
164
165impl std::error::Error for Error {}
166
167impl From<std::io::Error> for Error {
168 fn from(e: std::io::Error) -> Self {
169 Error::new(ErrorClass::Io, e.to_string())
170 }
171}
172
173macro_rules! ctor {
174 ($name:ident, $class:ident) => {
175 pub fn $name(message: impl Into<String>) -> Self {
177 Error::new(ErrorClass::$class, message)
178 }
179 };
180}
181
182impl Error {
183 ctor!(io, Io);
184 ctor!(usage, Usage);
185 ctor!(invalid_container, InvalidContainer);
186 ctor!(unsupported_version, UnsupportedVersion);
187 ctor!(unsupported_feature, UnsupportedFeature);
188 ctor!(integrity_mismatch, IntegrityMismatch);
189 ctor!(resource_limit, ResourceLimit);
190 ctor!(invalid_graph, InvalidGraph);
191 ctor!(invalid_model, InvalidModel);
192 ctor!(entropy_decode, EntropyDecode);
193 ctor!(invalid_pdf_structure, InvalidPdfStructure);
194 ctor!(codec_replay, CodecReplay);
195 ctor!(missing_external_object, MissingExternalObject);
196 ctor!(coverage_violation, CoverageViolation);
197 ctor!(reconstruction_mismatch, ReconstructionMismatch);
198 ctor!(cancelled, Cancelled);
199 ctor!(invalid_zip_structure, InvalidZipStructure);
200 ctor!(invalid_xml_structure, InvalidXmlStructure);
201 ctor!(invalid_package_structure, InvalidPackageStructure);
202 ctor!(invalid_json_structure, InvalidJsonStructure);
203 ctor!(invalid_yaml_structure, InvalidYamlStructure);
204 ctor!(internal_invariant, InternalInvariant);
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn exit_codes_are_distinct_and_stable() {
213 let classes = [
215 ErrorClass::Io,
216 ErrorClass::Usage,
217 ErrorClass::InvalidContainer,
218 ErrorClass::UnsupportedVersion,
219 ErrorClass::UnsupportedFeature,
220 ErrorClass::IntegrityMismatch,
221 ErrorClass::ResourceLimit,
222 ErrorClass::InvalidGraph,
223 ErrorClass::InvalidModel,
224 ErrorClass::EntropyDecode,
225 ErrorClass::InvalidPdfStructure,
226 ErrorClass::CodecReplay,
227 ErrorClass::MissingExternalObject,
228 ErrorClass::CoverageViolation,
229 ErrorClass::ReconstructionMismatch,
230 ErrorClass::Cancelled,
231 ErrorClass::InvalidZipStructure,
232 ErrorClass::InvalidXmlStructure,
233 ErrorClass::InvalidPackageStructure,
234 ErrorClass::InternalInvariant,
235 ];
236 let mut codes: Vec<i32> = classes.iter().map(|c| c.exit_code()).collect();
237 let n = codes.len();
238 codes.sort_unstable();
239 codes.dedup();
240 assert_eq!(codes.len(), n, "exit codes must be unique");
241 assert_eq!(ErrorClass::InvalidContainer.exit_code(), 4);
242 }
243
244 #[test]
245 fn display_includes_class() {
246 let e = Error::invalid_container("bad magic");
247 assert_eq!(e.to_string(), "InvalidContainer: bad magic");
248 }
249}