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