1use std::{
16 backtrace::Backtrace,
17 fmt::{Debug, Display},
18 sync::Arc,
19};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum ErrorKind {
24 Io,
26 External,
28 Config,
30 ChannelClosed,
32 TaskCancelled,
34 Join,
36 Parse,
38 BufferSizeLimit,
44 ChecksumMismatch,
46 MagicMismatch,
48 OutOfRange,
50 NoSpace,
52 Closed,
54 Recover,
56}
57
58impl ErrorKind {
59 pub fn into_static(self) -> &'static str {
61 self.into()
62 }
63}
64
65impl Display for ErrorKind {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "{}", self.into_static())
68 }
69}
70
71impl From<ErrorKind> for &'static str {
72 fn from(v: ErrorKind) -> &'static str {
73 match v {
74 ErrorKind::Io => "I/O error",
75 ErrorKind::External => "External error",
76 ErrorKind::Config => "Config error",
77 ErrorKind::ChannelClosed => "Channel closed",
78 ErrorKind::TaskCancelled => "Task cancelled",
79 ErrorKind::Join => "Join error",
80 ErrorKind::Parse => "Parse error",
81 ErrorKind::BufferSizeLimit => "Buffer size limit exceeded",
82 ErrorKind::ChecksumMismatch => "Checksum mismatch",
83 ErrorKind::MagicMismatch => "Magic mismatch",
84 ErrorKind::OutOfRange => "Out of range",
85 ErrorKind::NoSpace => "No space",
86 ErrorKind::Closed => "Closed",
87 ErrorKind::Recover => "Recover error",
88 }
89 }
90}
91
92pub struct Error {
161 kind: ErrorKind,
162 message: String,
163
164 context: Vec<(&'static str, String)>,
165
166 source: Option<Arc<anyhow::Error>>,
167 backtrace: Option<Arc<Backtrace>>,
168}
169
170impl Debug for Error {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 if f.alternate() {
174 let mut de = f.debug_struct("Error");
175 de.field("kind", &self.kind);
176 de.field("message", &self.message);
177 de.field("context", &self.context);
178 de.field("source", &self.source);
179 de.field("backtrace", &self.backtrace);
180 return de.finish();
181 }
182
183 write!(f, "{}", self.kind)?;
184 if !self.message.is_empty() {
185 write!(f, " => {}", self.message)?;
186 }
187 writeln!(f)?;
188
189 if !self.context.is_empty() {
190 writeln!(f)?;
191 writeln!(f, "Context:")?;
192 for (k, v) in self.context.iter() {
193 writeln!(f, " {}: {}", k, v)?;
194 }
195 }
196
197 if let Some(source) = &self.source {
198 writeln!(f)?;
199 writeln!(f, "Source:")?;
200 writeln!(f, " {source:#}")?;
201 }
202
203 if let Some(backtrace) = &self.backtrace {
204 writeln!(f)?;
205 writeln!(f, "Backtrace:")?;
206 writeln!(f, "{backtrace}")?;
207 }
208
209 Ok(())
210 }
211}
212
213impl Display for Error {
214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215 write!(f, "{}", self.kind)?;
216
217 if !self.context.is_empty() {
218 write!(f, ", context: {{ ")?;
219 let mut iter = self.context.iter().peekable();
220 while let Some((k, v)) = iter.next() {
221 write!(f, "{}: {}", k, v)?;
222 if iter.peek().is_some() {
223 write!(f, ", ")?;
224 }
225 }
226 write!(f, " }}")?;
227 }
228
229 if !self.message.is_empty() {
230 write!(f, " => {}", self.message)?;
231 }
232
233 if let Some(source) = &self.source {
234 write!(f, ", source: {source}")?;
235 }
236
237 Ok(())
238 }
239}
240
241impl std::error::Error for Error {
242 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
243 self.source.as_ref().map(|v| v.as_ref().as_ref())
244 }
245}
246
247impl Clone for Error {
251 fn clone(&self) -> Self {
252 Self {
253 kind: self.kind,
254 message: self.message.clone(),
255 context: self.context.clone(),
256 source: self.source.clone(),
257 backtrace: self.backtrace.clone(),
258 }
259 }
260}
261
262impl Error {
263 pub fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
275 Self {
276 kind,
277 message: message.into(),
278 context: Vec::new(),
279 source: None,
280 backtrace: Some(Arc::new(Backtrace::capture())),
281 }
282 }
283
284 pub fn with_context(mut self, key: &'static str, value: impl ToString) -> Self {
286 self.context.push((key, value.to_string()));
287 self
288 }
289
290 pub fn with_source(mut self, source: impl Into<anyhow::Error>) -> Self {
296 debug_assert!(self.source.is_none(), "the source error has been set");
297 self.source = Some(Arc::new(source.into()));
298 self
299 }
300
301 pub fn kind(&self) -> ErrorKind {
303 self.kind
304 }
305
306 pub fn message(&self) -> &str {
308 &self.message
309 }
310
311 pub fn context(&self) -> &Vec<(&'static str, String)> {
313 &self.context
314 }
315
316 pub fn backtrace(&self) -> Option<&Backtrace> {
318 self.backtrace.as_deref()
319 }
320
321 pub fn source(&self) -> Option<&anyhow::Error> {
323 self.source.as_deref()
324 }
325
326 pub fn downcast_ref<E>(&self) -> Option<&E>
328 where
329 E: std::error::Error + Send + Sync + 'static,
330 {
331 self.source.as_deref().and_then(|e| e.downcast_ref::<E>())
332 }
333}
334
335pub type Result<T> = std::result::Result<T, Error>;
337
338impl Error {
340 pub fn raw_os_io_error(raw: i32) -> Self {
342 let source = std::io::Error::from_raw_os_error(raw);
343 Self::io_error(source)
344 }
345
346 pub fn io_error(source: std::io::Error) -> Self {
348 match source.kind() {
349 std::io::ErrorKind::WriteZero => Error::new(ErrorKind::BufferSizeLimit, "coding error").with_source(source),
350 _ => Error::new(ErrorKind::Io, "coding error").with_source(source),
351 }
352 }
353
354 #[cfg(feature = "serde")]
356 pub fn bincode_error(source: bincode::Error) -> Self {
357 match *source {
358 bincode::ErrorKind::SizeLimit => Error::new(ErrorKind::BufferSizeLimit, "coding error").with_source(source),
359 bincode::ErrorKind::Io(e) => Self::io_error(e),
360 _ => Error::new(ErrorKind::External, "coding error").with_source(source),
361 }
362 }
363
364 pub fn no_space(capacity: usize, allocated: usize, required: usize) -> Self {
366 Error::new(ErrorKind::NoSpace, "not enough space left")
367 .with_context("capacity", capacity)
368 .with_context("allocated", allocated)
369 .with_context("required", required)
370 }
371
372 pub fn join(source: tokio::task::JoinError) -> Self {
374 Error::new(ErrorKind::Join, "task join error").with_source(source)
375 }
376}
377
378#[cfg(test)]
379mod tests {
380
381 use super::*;
382
383 fn is_send_sync_static<T: Send + Sync + 'static>() {}
384
385 #[test]
386 fn test_send_sync_static() {
387 is_send_sync_static::<Error>();
388 }
389
390 #[derive(Debug, Clone, PartialEq, Eq)]
391 struct TestError(String);
392
393 impl std::fmt::Display for TestError {
394 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
395 write!(f, "TestError: {}", self.0)
396 }
397 }
398
399 impl std::error::Error for TestError {}
400
401 #[test]
402 fn test_error_display() {
403 let io_error = std::io::Error::other("some I/O error");
404 let err = Error::new(ErrorKind::Io, "an I/O error occurred")
405 .with_source(io_error)
406 .with_context("k1", "v1")
407 .with_context("k2", "v2");
408
409 assert_eq!(
410 "I/O error, context: { k1: v1, k2: v2 } => an I/O error occurred, source: some I/O error",
411 err.to_string()
412 );
413 }
414
415 #[test]
416 fn test_error_downcast() {
417 let inner = TestError("Error or not error, that is a question.".to_string());
418 let err = Error::new(ErrorKind::External, "").with_source(inner.clone());
419
420 let downcasted = err.downcast_ref::<TestError>().unwrap();
421 assert_eq!(downcasted, &inner);
422 }
423
424 #[test]
425 fn test_error_format() {
426 let e = Error::new(ErrorKind::External, "external error")
427 .with_context("k1", "v2")
428 .with_context("k2", "v2")
429 .with_source(TestError("test error".into()));
430
431 println!("========== BEGIN DISPLAY FORMAT ==========");
432 println!("{e}");
433 println!("========== END DISPLAY FORMAT ==========");
434
435 println!();
436
437 println!("========== BEGIN DEBUG FORMAT ==========");
438 println!("{e:?}");
439 println!("========== END DEBUG FORMAT ==========");
440
441 println!();
442
443 println!("========== BEGIN DEBUG FORMAT (PRETTY) ==========");
444 println!("{e:#?}");
445 println!("========== END DEBUG FORMAT (PRETTY) ==========");
446 }
447}