1pub use ryg_rans_rs_core::{DecodeError, EncodeError, ModelError};
11
12use std::fmt;
13use std::path::PathBuf;
14use std::sync::Arc;
15
16#[derive(Debug, Clone)]
27pub enum AppError {
28 Io(IoError),
30 Format(FormatError),
32 Model(ModelError),
34 Codec(CodecError),
36 Integrity(IntegrityError),
38 ResourceLimit(ResourceLimitError),
40 Backend(BackendError),
42 Comparison(ComparisonError),
44 ExternalOracle(OracleError),
46 InternalInvariant(InternalInvariantError),
48}
49
50impl fmt::Display for AppError {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 match self {
53 AppError::Io(e) => write!(f, "I/O error: {}", e),
54 AppError::Format(e) => write!(f, "format error: {}", e),
55 AppError::Model(e) => write!(f, "model error: {}", e),
56 AppError::Codec(e) => write!(f, "codec error: {}", e),
57 AppError::Integrity(e) => write!(f, "integrity error: {}", e),
58 AppError::ResourceLimit(e) => write!(f, "resource limit: {}", e),
59 AppError::Backend(e) => write!(f, "backend error: {}", e),
60 AppError::Comparison(e) => write!(f, "comparison error: {}", e),
61 AppError::ExternalOracle(e) => write!(f, "oracle error: {}", e),
62 AppError::InternalInvariant(e) => write!(f, "internal error: {}", e),
63 }
64 }
65}
66
67impl std::error::Error for AppError {
68 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
69 match self {
70 AppError::Io(e) => Some(e),
71 AppError::Format(e) => Some(e),
72 AppError::Model(e) => Some(e),
73 AppError::Codec(e) => Some(e),
74 AppError::Integrity(e) => Some(e),
75 AppError::ResourceLimit(e) => Some(e),
76 AppError::Backend(e) => Some(e),
77 AppError::Comparison(e) => Some(e),
78 AppError::ExternalOracle(e) => Some(e),
79 AppError::InternalInvariant(e) => Some(e),
80 }
81 }
82}
83
84impl AppError {
85 pub fn kind(&self) -> &'static str {
87 match self {
88 AppError::Io(_) => "io_error",
89 AppError::Format(_) => "format_error",
90 AppError::Model(_) => "model_error",
91 AppError::Codec(_) => "codec_error",
92 AppError::Integrity(_) => "integrity_failure",
93 AppError::ResourceLimit(_) => "resource_limit",
94 AppError::Backend(_) => "backend_unavailable",
95 AppError::Comparison(_) => "comparison_mismatch",
96 AppError::ExternalOracle(_) => "oracle_error",
97 AppError::InternalInvariant(_) => "internal_invariant",
98 }
99 }
100
101 pub fn exit_code(&self) -> i32 {
103 match self {
104 AppError::Io(_) => 3,
105 AppError::Format(_) => 4,
106 AppError::Model(_) => 4,
107 AppError::Codec(_) => 4,
108 AppError::Integrity(_) => 5,
109 AppError::ResourceLimit(_) => 7,
110 AppError::Backend(_) => 9,
111 AppError::Comparison(_) => 8,
112 AppError::ExternalOracle(_) => 3,
113 AppError::InternalInvariant(_) => 10,
114 }
115 }
116
117 pub fn to_json_value(&self) -> serde_json::Value {
119 serde_json::json!({
120 "kind": self.kind(),
121 "message": self.to_string(),
122 })
123 }
124}
125
126#[derive(Debug, Clone)]
131pub struct IoError {
132 pub path: Option<PathBuf>,
133 pub detail: String,
134}
135
136impl fmt::Display for IoError {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 if let Some(path) = &self.path {
139 write!(f, "{} (path: {})", self.detail, path.display())
140 } else {
141 write!(f, "{}", self.detail)
142 }
143 }
144}
145
146impl std::error::Error for IoError {}
147
148#[derive(Debug, Clone)]
149pub struct FormatError {
150 pub detail: String,
151 pub block_index: Option<u64>,
152 pub offset: Option<u64>,
153}
154
155impl fmt::Display for FormatError {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 write!(f, "{}", self.detail)?;
158 if let Some(block) = self.block_index {
159 write!(f, " (block {})", block)?;
160 }
161 if let Some(off) = self.offset {
162 write!(f, " (offset {})", off)?;
163 }
164 Ok(())
165 }
166}
167
168impl std::error::Error for FormatError {}
169
170#[derive(Debug, Clone)]
171pub struct CodecError {
172 pub detail: String,
173 pub codec_id: Option<u16>,
174}
175
176impl fmt::Display for CodecError {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 write!(f, "{}", self.detail)?;
179 if let Some(id) = self.codec_id {
180 write!(f, " (codec {})", id)?;
181 }
182 Ok(())
183 }
184}
185
186impl std::error::Error for CodecError {}
187
188#[derive(Debug, Clone)]
189pub struct IntegrityError {
190 pub detail: String,
191 pub block_index: Option<u64>,
192}
193
194impl fmt::Display for IntegrityError {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 write!(f, "{}", self.detail)?;
197 if let Some(block) = self.block_index {
198 write!(f, " (block {})", block)?;
199 }
200 Ok(())
201 }
202}
203
204impl std::error::Error for IntegrityError {}
205
206#[derive(Debug, Clone)]
207pub struct ResourceLimitError {
208 pub detail: String,
209 pub limit: u64,
210 pub requested: u64,
211}
212
213impl fmt::Display for ResourceLimitError {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(
216 f,
217 "{} (limit: {}, requested: {})",
218 self.detail, self.limit, self.requested
219 )
220 }
221}
222
223impl std::error::Error for ResourceLimitError {}
224
225#[derive(Debug, Clone)]
226pub struct BackendError {
227 pub detail: String,
228 pub backend: String,
229}
230
231impl fmt::Display for BackendError {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(f, "{} (backend: {})", self.detail, self.backend)
234 }
235}
236
237impl std::error::Error for BackendError {}
238
239#[derive(Debug, Clone)]
240pub struct ComparisonError {
241 pub detail: String,
242}
243
244impl fmt::Display for ComparisonError {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 write!(f, "{}", self.detail)
247 }
248}
249
250impl std::error::Error for ComparisonError {}
251
252#[derive(Debug, Clone)]
253pub struct OracleError {
254 pub detail: String,
255 pub exit_code: Option<i32>,
256}
257
258impl fmt::Display for OracleError {
259 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260 write!(f, "{}", self.detail)?;
261 if let Some(code) = self.exit_code {
262 write!(f, " (exit: {})", code)?;
263 }
264 Ok(())
265 }
266}
267
268impl std::error::Error for OracleError {}
269
270#[derive(Debug, Clone)]
271pub struct InternalInvariantError {
272 pub detail: String,
273}
274
275impl fmt::Display for InternalInvariantError {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(f, "internal invariant: {}", self.detail)
278 }
279}
280
281impl std::error::Error for InternalInvariantError {}
282
283impl From<std::io::Error> for AppError {
288 fn from(e: std::io::Error) -> Self {
289 AppError::Io(IoError {
290 path: None,
291 detail: e.to_string(),
292 })
293 }
294}
295
296impl From<ryg_rans_rs_core::ModelError> for AppError {
297 fn from(e: ryg_rans_rs_core::ModelError) -> Self {
298 AppError::Model(e)
299 }
300}
301
302impl From<ryg_rans_rs_core::EncodeError> for AppError {
303 fn from(_e: ryg_rans_rs_core::EncodeError) -> Self {
304 AppError::Codec(CodecError {
305 detail: "encode buffer too small".into(),
306 codec_id: None,
307 })
308 }
309}
310
311impl From<ryg_rans_rs_core::DecodeError> for AppError {
312 fn from(_e: ryg_rans_rs_core::DecodeError) -> Self {
313 AppError::Format(FormatError {
314 detail: "truncated stream".into(),
315 block_index: None,
316 offset: None,
317 })
318 }
319}
320
321impl From<String> for AppError {
322 fn from(s: String) -> Self {
323 AppError::InternalInvariant(InternalInvariantError { detail: s })
324 }
325}