1use crate::kind::ErrorKind;
2use serde::Serialize;
3use std::fmt;
4
5#[derive(Debug, Clone, Serialize)]
6pub struct AppError {
7 pub kind: ErrorKind,
8 pub context: Option<ErrorContext>,
9}
10
11#[derive(Debug, Clone, Serialize)]
12pub struct ErrorContext {
13 pub source: &'static str,
14 pub details: Option<String>,
15}
16
17impl AppError {
18 pub fn new(kind: ErrorKind) -> Self {
19 Self {
20 kind,
21 context: None,
22 }
23 }
24
25 pub fn with_context(mut self, source: &'static str, details: Option<String>) -> Self {
26 self.context = Some(ErrorContext { source, details });
27 self
28 }
29
30 pub fn unknown() -> Self {
31 Self::from(ErrorKind::unknown())
32 }
33}
34
35impl fmt::Display for AppError {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "{}", self.kind)?;
38 if let Some(ctx) = &self.context {
39 write!(f, " | Source: {} | Details: {:?}", ctx.source, ctx.details)?;
40 }
41 Ok(())
42 }
43}
44
45impl std::error::Error for AppError {
46 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
47 Some(&self.kind)
48 }
49}
50
51impl From<ErrorKind> for AppError {
52 fn from(value: ErrorKind) -> Self {
53 AppError::new(value)
54 }
55}