1use std::fmt::Display;
13
14use serde::Deserialize;
15
16#[derive(Debug, Deserialize)]
17pub struct ProblemDetails {
18 #[serde(rename = "type")]
19 p_type: ProblemType,
20 pub status: Option<u32>,
21 title: Option<String>,
22 detail: Option<String>,
23 limit: Option<String>,
24 request_id: Option<String>,
25}
26
27#[derive(Debug, Deserialize)]
28pub enum JMAPError {
29 #[serde(rename = "urn:ietf:params:jmap:error:unknownCapability")]
30 UnknownCapability,
31 #[serde(rename = "urn:ietf:params:jmap:error:notJSON")]
32 NotJSON,
33 #[serde(rename = "urn:ietf:params:jmap:error:notRequest")]
34 NotRequest,
35 #[serde(rename = "urn:ietf:params:jmap:error:limit")]
36 Limit,
37}
38
39#[derive(Debug, Deserialize)]
40#[serde(untagged)]
41pub enum ProblemType {
42 JMAP(JMAPError),
43 Other(String),
44}
45
46#[derive(Debug, Deserialize, PartialEq, Eq)]
47pub struct MethodError {
48 #[serde(rename = "type")]
49 pub p_type: MethodErrorType,
50}
51
52#[derive(Debug, Deserialize, PartialEq, Eq)]
53pub enum MethodErrorType {
54 #[serde(rename = "serverUnavailable")]
55 ServerUnavailable,
56 #[serde(rename = "serverFail")]
57 ServerFail,
58 #[serde(rename = "serverPartialFail")]
59 ServerPartialFail,
60 #[serde(rename = "unknownMethod")]
61 UnknownMethod,
62 #[serde(rename = "invalidArguments")]
63 InvalidArguments,
64 #[serde(rename = "invalidResultReference")]
65 InvalidResultReference,
66 #[serde(rename = "forbidden")]
67 Forbidden,
68 #[serde(rename = "accountNotFound")]
69 AccountNotFound,
70 #[serde(rename = "accountNotSupportedByMethod")]
71 AccountNotSupportedByMethod,
72 #[serde(rename = "accountReadOnly")]
73 AccountReadOnly,
74 #[serde(rename = "requestTooLarge")]
75 RequestTooLarge,
76 #[serde(rename = "cannotCalculateChanges")]
77 CannotCalculateChanges,
78 #[serde(rename = "stateMismatch")]
79 StateMismatch,
80 #[serde(rename = "alreadyExists")]
81 AlreadyExists,
82 #[serde(rename = "fromAccountNotFound")]
83 FromAccountNotFound,
84 #[serde(rename = "fromAccountNotSupportedByMethod")]
85 FromAccountNotSupportedByMethod,
86 #[serde(rename = "anchorNotFound")]
87 AnchorNotFound,
88 #[serde(rename = "unsupportedSort")]
89 UnsupportedSort,
90 #[serde(rename = "unsupportedFilter")]
91 UnsupportedFilter,
92 #[serde(rename = "tooManyChanges")]
93 TooManyChanges,
94}
95
96impl ProblemDetails {
97 pub fn new(
98 p_type: ProblemType,
99 status: Option<u32>,
100 title: Option<String>,
101 detail: Option<String>,
102 limit: Option<String>,
103 request_id: Option<String>,
104 ) -> Self {
105 ProblemDetails {
106 p_type,
107 status,
108 title,
109 detail,
110 limit,
111 request_id,
112 }
113 }
114
115 pub fn error(&self) -> &ProblemType {
116 &self.p_type
117 }
118
119 pub fn status(&self) -> Option<u32> {
120 self.status
121 }
122
123 pub fn title(&self) -> Option<&str> {
124 self.title.as_deref()
125 }
126
127 pub fn detail(&self) -> Option<&str> {
128 self.detail.as_deref()
129 }
130
131 pub fn limit(&self) -> Option<&str> {
132 self.limit.as_deref()
133 }
134
135 pub fn request_id(&self) -> Option<&str> {
136 self.request_id.as_deref()
137 }
138}
139
140impl MethodError {
141 pub fn error(&self) -> &MethodErrorType {
142 &self.p_type
143 }
144}
145
146impl Display for MethodError {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 match self.p_type {
149 MethodErrorType::ServerUnavailable => write!(f, "Server unavailable"),
150 MethodErrorType::ServerFail => write!(f, "Server fail"),
151 MethodErrorType::ServerPartialFail => write!(f, "Server partial fail"),
152 MethodErrorType::UnknownMethod => write!(f, "Unknown method"),
153 MethodErrorType::InvalidArguments => write!(f, "Invalid arguments"),
154 MethodErrorType::InvalidResultReference => write!(f, "Invalid result reference"),
155 MethodErrorType::Forbidden => write!(f, "Forbidden"),
156 MethodErrorType::AccountNotFound => write!(f, "Account not found"),
157 MethodErrorType::AccountNotSupportedByMethod => {
158 write!(f, "Account not supported by method")
159 }
160 MethodErrorType::AccountReadOnly => write!(f, "Account read only"),
161 MethodErrorType::RequestTooLarge => write!(f, "Request too large"),
162 MethodErrorType::CannotCalculateChanges => write!(f, "Cannot calculate changes"),
163 MethodErrorType::StateMismatch => write!(f, "State mismatch"),
164 MethodErrorType::AlreadyExists => write!(f, "Already exists"),
165 MethodErrorType::FromAccountNotFound => write!(f, "From account not found"),
166 MethodErrorType::FromAccountNotSupportedByMethod => {
167 write!(f, "From account not supported by method")
168 }
169 MethodErrorType::AnchorNotFound => write!(f, "Anchor not found"),
170 MethodErrorType::UnsupportedSort => write!(f, "Unsupported sort"),
171 MethodErrorType::UnsupportedFilter => write!(f, "Unsupported filter"),
172 MethodErrorType::TooManyChanges => write!(f, "Too many changes"),
173 }
174 }
175}
176
177impl Display for ProblemDetails {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 match &self.p_type {
180 ProblemType::JMAP(err) => match err {
181 JMAPError::UnknownCapability => write!(f, "Unknown capability")?,
182 JMAPError::NotJSON => write!(f, "Not JSON")?,
183 JMAPError::NotRequest => write!(f, "Not request")?,
184 JMAPError::Limit => write!(f, "Limit")?,
185 },
186 ProblemType::Other(err) => f.write_str(err.as_str())?,
187 }
188
189 if let Some(status) = self.status {
190 write!(f, " (status {})", status)?
191 }
192
193 if let Some(title) = &self.title {
194 write!(f, ": {}", title)?
195 }
196
197 if let Some(detail) = &self.detail {
198 write!(f, ". Details: {}", detail)?
199 }
200
201 Ok(())
202 }
203}