1use hyper::http::{uri::InvalidUri, StatusCode};
2use serde::Deserialize;
3use serde_json::Error as JsonError;
4use std::fmt::Display;
5
6#[derive(Deserialize, Debug)]
7pub(crate) struct ApiErrorMessage {
8 message: String,
9}
10
11impl Display for ApiErrorMessage {
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13 self.message.fmt(f)
14 }
15}
16
17impl std::error::Error for ApiErrorMessage {}
18
19#[derive(Deserialize, Debug)]
20#[serde(tag = "status", rename_all = "UPPERCASE")]
21pub(crate) enum ApiResponse<T> {
22 Success(T),
23 Error(ApiErrorMessage),
24}
25
26impl<T> From<ApiResponse<T>> for std::result::Result<T, ApiErrorMessage> {
27 fn from(value: ApiResponse<T>) -> Self {
28 match value {
29 ApiResponse::Success(s) => Ok(s),
30 ApiResponse::Error(e) => Err(e),
31 }
32 }
33}
34
35#[derive(Debug)]
37pub(crate) struct ApiError {
38 status: StatusCode,
39 error: Option<ApiErrorMessage>,
40}
41
42impl Display for ApiError {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 let Self { status, error } = self;
45 if let Some(error) = error {
46 f.write_fmt(format_args!("[{status}] {error}"))
47 } else {
48 f.write_fmt(format_args!("Invalid status code {status}"))
49 }
50 }
51}
52
53#[derive(Debug)]
54pub(crate) enum ErrorImpl<T: std::error::Error + Send + Sync + 'static> {
55 ApiError(ApiError),
56 TransportError(T),
57 SerializationError(JsonError),
58 DeserializationError(JsonError),
59 InvalidUri(InvalidUri),
60}
61
62impl<T: std::error::Error + Send + Sync + 'static> From<(StatusCode, Option<ApiErrorMessage>)>
63 for ErrorImpl<T>
64{
65 fn from(value: (StatusCode, Option<ApiErrorMessage>)) -> Self {
66 Self::ApiError(ApiError {
67 status: value.0,
68 error: value.1,
69 })
70 }
71}
72
73impl<T: std::error::Error + Send + Sync + 'static> From<hyper::http::uri::InvalidUri>
74 for ErrorImpl<T>
75{
76 fn from(value: hyper::http::uri::InvalidUri) -> Self {
77 Self::InvalidUri(value)
78 }
79}
80
81impl<T: std::error::Error + Send + Sync + 'static> Display for ErrorImpl<T> {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 Self::ApiError(api_error) => api_error.fmt(f),
85 Self::DeserializationError(_) => f.write_str("failed to deserialize response"),
86 Self::SerializationError(_) => f.write_str("failed to serialize request"),
87 Self::TransportError(_) => f.write_str("failed to send request or recieve response"),
88 Self::InvalidUri(_) => f.write_str("invalid uri"),
89 }
90 }
91}
92
93impl<T: std::error::Error + Send + Sync + 'static> std::error::Error for ErrorImpl<T> {
94 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
95 match self {
96 Self::ApiError { .. } => None,
97 Self::TransportError(t) => Some(t),
98 Self::SerializationError(s) | Self::DeserializationError(s) => Some(s),
99 Self::InvalidUri(u) => Some(u),
100 }
101 }
102}
103
104pub struct Error<T: std::error::Error + Send + Sync + 'static>(ErrorImpl<T>);
108
109impl<T: std::error::Error + Send + Sync + 'static> Error<T> {
110 pub fn as_transport_error(&self) -> Option<&T> {
113 if let ErrorImpl::TransportError(e) = &self.0 {
114 Some(e)
115 } else {
116 None
117 }
118 }
119 pub fn into_transport_error(self) -> Option<T> {
122 if let ErrorImpl::TransportError(e) = self.0 {
123 Some(e)
124 } else {
125 None
126 }
127 }
128}
129
130impl<T: std::error::Error + Send + Sync + 'static> std::fmt::Debug for Error<T> {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 std::fmt::Debug::fmt(&self.0, f)
133 }
134}
135
136impl<T: std::error::Error + Send + Sync + 'static> Display for Error<T> {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 std::fmt::Display::fmt(&self.0, f)
139 }
140}
141
142impl<T: std::error::Error + Send + Sync + 'static> std::error::Error for Error<T> {
143 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
144 self.0.source()
145 }
146}
147
148impl<E: std::error::Error + Send + Sync + 'static, T> From<T> for Error<E>
149where
150 T: Into<ErrorImpl<E>>,
151{
152 fn from(value: T) -> Self {
153 Self(value.into())
154 }
155}