1use std::fmt;
2
3#[derive(Debug, PartialEq, Eq)]
5pub struct LocalProtocolError {
6 pub message: String,
8 pub code: u16,
10}
11
12impl From<(String, u16)> for LocalProtocolError {
13 fn from(value: (String, u16)) -> Self {
14 LocalProtocolError {
15 message: value.0,
16 code: value.1,
17 }
18 }
19}
20
21impl From<(&str, u16)> for LocalProtocolError {
22 fn from(value: (&str, u16)) -> Self {
23 LocalProtocolError {
24 message: value.0.to_string(),
25 code: value.1,
26 }
27 }
28}
29
30impl From<String> for LocalProtocolError {
31 fn from(value: String) -> Self {
32 LocalProtocolError {
33 message: value,
34 code: 400,
35 }
36 }
37}
38
39impl From<&str> for LocalProtocolError {
40 fn from(value: &str) -> Self {
41 LocalProtocolError {
42 message: value.to_string(),
43 code: 400,
44 }
45 }
46}
47
48impl LocalProtocolError {
49 pub(crate) fn _reraise_as_remote_protocol_error(self) -> RemoteProtocolError {
50 RemoteProtocolError {
51 message: self.message,
52 code: self.code,
53 }
54 }
55}
56
57impl fmt::Display for LocalProtocolError {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 write!(f, "{} (status code {})", self.message, self.code)
60 }
61}
62
63impl std::error::Error for LocalProtocolError {}
64
65#[derive(Debug, PartialEq, Eq)]
67pub struct RemoteProtocolError {
68 pub message: String,
70 pub code: u16,
72}
73
74impl From<(String, u16)> for RemoteProtocolError {
75 fn from(value: (String, u16)) -> Self {
76 RemoteProtocolError {
77 message: value.0,
78 code: value.1,
79 }
80 }
81}
82
83impl From<(&str, u16)> for RemoteProtocolError {
84 fn from(value: (&str, u16)) -> Self {
85 RemoteProtocolError {
86 message: value.0.to_string(),
87 code: value.1,
88 }
89 }
90}
91
92impl From<String> for RemoteProtocolError {
93 fn from(value: String) -> Self {
94 RemoteProtocolError {
95 message: value,
96 code: 400,
97 }
98 }
99}
100
101impl From<&str> for RemoteProtocolError {
102 fn from(value: &str) -> Self {
103 RemoteProtocolError {
104 message: value.to_string(),
105 code: 400,
106 }
107 }
108}
109
110impl fmt::Display for RemoteProtocolError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(f, "{} (status code {})", self.message, self.code)
113 }
114}
115
116impl std::error::Error for RemoteProtocolError {}
117
118#[derive(Debug, PartialEq, Eq)]
120pub enum ProtocolError {
121 LocalProtocolError(LocalProtocolError),
123 RemoteProtocolError(RemoteProtocolError),
125}
126
127impl From<LocalProtocolError> for ProtocolError {
128 fn from(value: LocalProtocolError) -> Self {
129 ProtocolError::LocalProtocolError(value)
130 }
131}
132
133impl From<RemoteProtocolError> for ProtocolError {
134 fn from(value: RemoteProtocolError) -> Self {
135 ProtocolError::RemoteProtocolError(value)
136 }
137}
138
139impl fmt::Display for ProtocolError {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self {
142 Self::LocalProtocolError(error) => write!(f, "local protocol error: {}", error),
143 Self::RemoteProtocolError(error) => write!(f, "remote protocol error: {}", error),
144 }
145 }
146}
147
148impl std::error::Error for ProtocolError {
149 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
150 match self {
151 Self::LocalProtocolError(error) => Some(error),
152 Self::RemoteProtocolError(error) => Some(error),
153 }
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use std::error::Error;
161
162 #[test]
163 fn protocol_errors_implement_display_and_error() {
164 let local = LocalProtocolError::from(("bad request", 400));
165 assert_eq!(local.to_string(), "bad request (status code 400)");
166
167 let remote = RemoteProtocolError::from(("bad gateway", 502));
168 assert_eq!(remote.to_string(), "bad gateway (status code 502)");
169
170 let error = ProtocolError::from(LocalProtocolError::from(("invalid", 400)));
171 assert_eq!(
172 error.to_string(),
173 "local protocol error: invalid (status code 400)"
174 );
175 assert!(error.source().is_some());
176 }
177}