1use std::fmt;
2use thiserror::Error as ThisError;
3
4#[derive(Debug, ThisError)]
11#[error("{message}")]
12pub struct InternalError {
13 pub class: ErrorClass,
14 pub origin: ErrorOrigin,
15 pub message: String,
16
17 pub detail: Option<ErrorDetail>,
20}
21
22impl InternalError {
23 pub fn new(class: ErrorClass, origin: ErrorOrigin, message: impl Into<String>) -> Self {
27 let message = message.into();
28
29 let detail = match (class, origin) {
30 (ErrorClass::Corruption, ErrorOrigin::Store) => {
31 Some(ErrorDetail::Store(StoreError::Corrupt {
32 message: message.clone(),
33 }))
34 }
35 (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
36 Some(ErrorDetail::Store(StoreError::InvariantViolation {
37 message: message.clone(),
38 }))
39 }
40 _ => None,
41 };
42
43 Self {
44 class,
45 origin,
46 message,
47 detail,
48 }
49 }
50
51 pub fn store_not_found(key: impl Into<String>) -> Self {
52 let key = key.into();
53
54 Self {
55 class: ErrorClass::NotFound,
56 origin: ErrorOrigin::Store,
57 message: format!("data key not found: {key}"),
58 detail: Some(ErrorDetail::Store(StoreError::NotFound { key })),
59 }
60 }
61
62 #[must_use]
63 pub const fn is_not_found(&self) -> bool {
64 matches!(
65 self.detail,
66 Some(ErrorDetail::Store(StoreError::NotFound { .. }))
67 )
68 }
69
70 #[must_use]
71 pub fn display_with_class(&self) -> String {
72 format!("{}:{}: {}", self.origin, self.class, self.message)
73 }
74}
75
76impl From<crate::traits::ViewPatchError> for InternalError {
77 fn from(err: crate::traits::ViewPatchError) -> Self {
78 let class = match err.leaf() {
79 crate::traits::ViewPatchError::MissingKey { .. } => ErrorClass::NotFound,
80 _ => ErrorClass::Unsupported,
81 };
82
83 Self {
84 class,
85 origin: ErrorOrigin::Interface,
86 message: err.to_string(),
87 detail: Some(ErrorDetail::ViewPatch(err)),
88 }
89 }
90}
91
92#[derive(Debug, ThisError)]
100pub enum ErrorDetail {
101 #[error("{0}")]
102 Store(StoreError),
103 #[error("{0}")]
104 ViewPatch(crate::traits::ViewPatchError),
105 }
115
116#[derive(Debug, ThisError)]
124pub enum StoreError {
125 #[error("key not found: {key}")]
126 NotFound { key: String },
127
128 #[error("store corruption: {message}")]
129 Corrupt { message: String },
130
131 #[error("store invariant violation: {message}")]
132 InvariantViolation { message: String },
133}
134
135#[derive(Clone, Copy, Debug, Eq, PartialEq)]
142pub enum ErrorClass {
143 Corruption,
144 NotFound,
145 Internal,
146 Conflict,
147 Unsupported,
148 InvariantViolation,
149}
150
151impl fmt::Display for ErrorClass {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 let label = match self {
154 Self::Corruption => "corruption",
155 Self::NotFound => "not_found",
156 Self::Internal => "internal",
157 Self::Conflict => "conflict",
158 Self::Unsupported => "unsupported",
159 Self::InvariantViolation => "invariant_violation",
160 };
161 write!(f, "{label}")
162 }
163}
164
165#[derive(Clone, Copy, Debug, Eq, PartialEq)]
172pub enum ErrorOrigin {
173 Serialize,
174 Store,
175 Index,
176 Query,
177 Response,
178 Executor,
179 Interface,
180}
181
182impl fmt::Display for ErrorOrigin {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 let label = match self {
185 Self::Serialize => "serialize",
186 Self::Store => "store",
187 Self::Index => "index",
188 Self::Query => "query",
189 Self::Response => "response",
190 Self::Executor => "executor",
191 Self::Interface => "interface",
192 };
193 write!(f, "{label}")
194 }
195}