1use anyhow::anyhow;
2use http::StatusCode;
3use std::fmt::Display;
4
5pub trait ContextWrapper<T, E> {
6 fn anyhow(self) -> Result<T, anyhow::Error>;
7 fn anyhow_with(self, msg: impl AsRef<str>) -> Result<T, anyhow::Error>;
8
9 fn track(self) -> Self;
10 fn track_with(self, msg: impl AsRef<str>) -> Self;
11}
12
13pub trait ErrToMsg {
14 fn to_msg(self, loc: &std::panic::Location) -> String;
15 fn to_msg_with(self, msg: impl AsRef<str>, loc: &std::panic::Location) -> String;
16}
17
18impl<E: Display> ErrToMsg for E {
19 #[track_caller]
20 fn to_msg(self, loc: &std::panic::Location) -> String {
21 let e = self.to_string();
22
23 if e.is_empty() {
24 format!("\n- [{}:{}]", loc.file(), loc.line())
25 } else {
26 format!("\n- [{}:{}] {e}", loc.file(), loc.line())
27 }
28 }
29
30 #[track_caller]
31 fn to_msg_with(self, msg: impl AsRef<str>, loc: &std::panic::Location) -> String {
32 let e = self.to_string();
33 if e.is_empty() {
34 format!("\n- [{}:{}] {}", loc.file(), loc.line(), msg.as_ref())
35 } else {
36 format!("\n- [{}:{}] {} {e}", loc.file(), loc.line(), msg.as_ref())
37 }
38 }
39}
40
41impl<T, E: Display> ContextWrapper<T, E> for Result<T, E> {
42 #[track_caller]
43 fn anyhow(self) -> Result<T, anyhow::Error> {
44 match self {
45 Ok(v) => Ok(v),
46 Err(e) => Err(anyhow!(e.to_msg(std::panic::Location::caller()))),
47 }
48 }
49
50 #[track_caller]
51 fn anyhow_with(self, msg: impl AsRef<str>) -> Result<T, anyhow::Error> {
52 match self {
53 Ok(v) => Ok(v),
54 Err(e) => Err(anyhow!(e.to_msg_with(msg, std::panic::Location::caller()))),
55 }
56 }
57
58 #[track_caller]
59 fn track(self) -> Self {
60 if let Err(e) = &self {
61 tracing::error!(target: "dutils", "{}", e.to_msg(std::panic::Location::caller()));
62 }
63 self
64 }
65 #[track_caller]
66 fn track_with(self, msg: impl AsRef<str>) -> Self {
67 if let Err(e) = &self {
68 tracing::error!(target: "dutils", "{}", e.to_msg_with(msg, std::panic::Location::caller()));
69 }
70 self
71 }
72}
73
74impl<T> ContextWrapper<T, ()> for Option<T> {
75 #[track_caller]
76 fn anyhow(self) -> Result<T, anyhow::Error> {
77 match self {
78 Some(v) => Ok(v),
79 None => Err(anyhow!(
80 "Value is None".to_msg(std::panic::Location::caller())
81 )),
82 }
83 }
84
85 #[track_caller]
86 fn anyhow_with(self, msg: impl AsRef<str>) -> Result<T, anyhow::Error> {
87 match self {
88 Some(v) => Ok(v),
89 None => Err(anyhow!(
90 "Value is None".to_msg_with(msg, std::panic::Location::caller())
91 )),
92 }
93 }
94
95 #[track_caller]
96 fn track(self) -> Self {
97 if self.is_none() {
98 tracing::error!(target: "dutils", "{}", "Value is None".to_msg(std::panic::Location::caller()));
99 }
100 self
101 }
102 #[track_caller]
103 fn track_with(self, msg: impl AsRef<str>) -> Self {
104 if self.is_none() {
105 tracing::error!(target: "dutils", "{}", "Value is None".to_msg_with(msg, std::panic::Location::caller()));
106 }
107 self
108 }
109}
110
111fn api_err_response(status: StatusCode, msg: impl AsRef<str>) -> http::Response<String> {
112 http::Response::builder()
113 .status(status)
114 .body(serde_json::to_string(msg.as_ref()).unwrap())
115 .unwrap()
116}
117
118pub trait ApiError {
119 type Ok;
120 fn bad_request_from_error(self) -> core::result::Result<Self::Ok, http::Response<String>>;
121 fn bad_request(
122 self,
123 msg: impl AsRef<str>,
124 ) -> core::result::Result<Self::Ok, http::Response<String>>;
125 fn not_found(
126 self,
127 msg: impl AsRef<str>,
128 ) -> core::result::Result<Self::Ok, http::Response<String>>;
129 fn internal(
130 self,
131 msg: impl AsRef<str>,
132 ) -> core::result::Result<Self::Ok, http::Response<String>>;
133
134 fn internal_from_error(self) -> core::result::Result<Self::Ok, http::Response<String>>;
135}
136
137pub trait ApiErrorConflict {
138 type Ok;
139 fn conflict(
140 self,
141 msg: impl AsRef<str>,
142 ) -> core::result::Result<Self::Ok, http::Response<String>>;
143}
144
145impl ApiError for String {
146 type Ok = ();
147
148 fn bad_request_from_error(self) -> core::result::Result<Self::Ok, http::Response<String>> {
149 Err(api_err_response(StatusCode::BAD_REQUEST, self))
150 }
151
152 fn bad_request(
153 self,
154 msg: impl AsRef<str>,
155 ) -> core::result::Result<Self::Ok, http::Response<String>> {
156 Err(api_err_response(StatusCode::BAD_REQUEST, msg))
157 }
158
159 fn not_found(
160 self,
161 msg: impl AsRef<str>,
162 ) -> core::result::Result<Self::Ok, http::Response<String>> {
163 Err(api_err_response(StatusCode::NOT_FOUND, msg))
164 }
165
166 fn internal(
167 self,
168 msg: impl AsRef<str>,
169 ) -> core::result::Result<Self::Ok, http::Response<String>> {
170 Err(api_err_response(StatusCode::INTERNAL_SERVER_ERROR, msg))
171 }
172
173 fn internal_from_error(self) -> core::result::Result<Self::Ok, http::Response<String>> {
174 Err(api_err_response(StatusCode::INTERNAL_SERVER_ERROR, self))
175 }
176}
177
178impl ApiError for &'_ str {
179 type Ok = ();
180
181 fn bad_request_from_error(self) -> core::result::Result<Self::Ok, http::Response<String>> {
182 Err(api_err_response(StatusCode::BAD_REQUEST, self))
183 }
184
185 fn bad_request(
186 self,
187 msg: impl AsRef<str>,
188 ) -> core::result::Result<Self::Ok, http::Response<String>> {
189 Err(api_err_response(StatusCode::BAD_REQUEST, msg))
190 }
191
192 fn not_found(
193 self,
194 msg: impl AsRef<str>,
195 ) -> core::result::Result<Self::Ok, http::Response<String>> {
196 Err(api_err_response(StatusCode::NOT_FOUND, msg))
197 }
198
199 fn internal(
200 self,
201 msg: impl AsRef<str>,
202 ) -> core::result::Result<Self::Ok, http::Response<String>> {
203 Err(api_err_response(StatusCode::INTERNAL_SERVER_ERROR, msg))
204 }
205
206 fn internal_from_error(self) -> core::result::Result<Self::Ok, http::Response<String>> {
207 Err(api_err_response(StatusCode::INTERNAL_SERVER_ERROR, self))
208 }
209}
210
211impl<T, E: Display> ApiError for core::result::Result<T, E> {
212 type Ok = T;
213
214 fn bad_request_from_error(self) -> core::result::Result<T, http::Response<String>> {
215 match self {
216 Ok(a) => Ok(a),
217 Err(e) => Err(api_err_response(StatusCode::BAD_REQUEST, e.to_string())),
218 }
219 }
220
221 fn bad_request(self, msg: impl AsRef<str>) -> core::result::Result<T, http::Response<String>> {
222 match self {
223 Ok(a) => Ok(a),
224 Err(_) => Err(api_err_response(StatusCode::BAD_REQUEST, msg)),
225 }
226 }
227
228 fn not_found(self, msg: impl AsRef<str>) -> core::result::Result<T, http::Response<String>> {
229 match self {
230 Ok(a) => Ok(a),
231 Err(_) => Err(api_err_response(StatusCode::NOT_FOUND, msg)),
232 }
233 }
234
235 fn internal(self, msg: impl AsRef<str>) -> core::result::Result<T, http::Response<String>> {
236 match self {
237 Ok(a) => Ok(a),
238 Err(_) => Err(api_err_response(StatusCode::INTERNAL_SERVER_ERROR, msg)),
239 }
240 }
241
242 fn internal_from_error(self) -> core::result::Result<T, http::Response<String>> {
243 match self {
244 Ok(a) => Ok(a),
245 Err(e) => Err(api_err_response(
246 StatusCode::INTERNAL_SERVER_ERROR,
247 e.to_string(),
248 )),
249 }
250 }
251}
252
253impl<T> ApiError for Option<T> {
254 type Ok = T;
255
256 fn bad_request_from_error(self) -> core::result::Result<T, http::Response<String>> {
257 match self {
258 Some(a) => Ok(a),
259 None => Err(api_err_response(StatusCode::BAD_REQUEST, "No value")),
260 }
261 }
262
263 fn bad_request(self, msg: impl AsRef<str>) -> core::result::Result<T, http::Response<String>> {
264 match self {
265 Some(a) => Ok(a),
266 None => Err(api_err_response(StatusCode::BAD_REQUEST, msg)),
267 }
268 }
269
270 fn not_found(self, msg: impl AsRef<str>) -> core::result::Result<T, http::Response<String>> {
271 match self {
272 Some(a) => Ok(a),
273 None => Err(api_err_response(StatusCode::NOT_FOUND, msg)),
274 }
275 }
276
277 fn internal(self, msg: impl AsRef<str>) -> core::result::Result<T, http::Response<String>> {
278 match self {
279 Some(a) => Ok(a),
280 None => Err(api_err_response(StatusCode::INTERNAL_SERVER_ERROR, msg)),
281 }
282 }
283
284 fn internal_from_error(self) -> core::result::Result<T, http::Response<String>> {
285 match self {
286 Some(a) => Ok(a),
287 None => Err(api_err_response(
288 StatusCode::INTERNAL_SERVER_ERROR,
289 "No value",
290 )),
291 }
292 }
293}
294
295impl<T> ApiErrorConflict for Option<T> {
296 type Ok = ();
297
298 fn conflict(self, msg: impl AsRef<str>) -> core::result::Result<(), http::Response<String>> {
299 match self {
300 None => Ok(()),
301 Some(_) => Err(api_err_response(StatusCode::CONFLICT, msg)),
302 }
303 }
304}
305
306pub trait ToResult<T> {
307 fn to_result(self) -> Result<T, anyhow::Error>;
308}
309
310impl<T> ToResult<T> for T {
311 fn to_result(self) -> Result<T, anyhow::Error> {
312 Ok(self)
313 }
314}