1use core::fmt;
3use hyper::{
4 header::{InvalidHeaderName, InvalidHeaderValue},
5 Error as RequestError,
6};
7use serde::Deserialize;
8use std::{convert::Infallible, error::Error as StdError};
9use std::{fmt::Display, result};
10
11pub type Result<T> = result::Result<T, Error>;
13
14#[derive(Debug)]
16pub struct ValueError(String);
17
18impl ValueError {
19 pub fn new<T: Into<String>>(value: T) -> Self {
20 Self(value.into())
21 }
22}
23
24impl Display for ValueError {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 write!(f, "value error: {}", self.0)
27 }
28}
29
30impl StdError for ValueError {}
31
32impl From<&str> for ValueError {
33 fn from(err: &str) -> Self {
34 Self(err.to_string())
35 }
36}
37
38impl From<InvalidHeaderValue> for ValueError {
39 fn from(err: InvalidHeaderValue) -> Self {
40 return ValueError(err.to_string());
41 }
42}
43
44impl From<InvalidHeaderName> for ValueError {
45 fn from(err: InvalidHeaderName) -> Self {
46 return ValueError(err.to_string());
47 }
48}
49
50impl From<Infallible> for ValueError {
51 fn from(err: Infallible) -> Self {
52 return ValueError(err.to_string());
53 }
54}
55
56#[derive(Debug)]
58pub struct XmlError(String);
59
60impl Display for XmlError {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(f, "xmlerror: {}", self.0)
63 }
64}
65
66impl StdError for XmlError {}
67
68impl From<crate::xml::error::Error> for XmlError {
69 fn from(err: crate::xml::error::Error) -> Self {
70 Self(err.to_string())
71 }
72}
73
74#[derive(Debug, Deserialize)]
77#[serde(rename_all = "PascalCase", rename="Error")]
78pub struct S3Error {
79 pub code: String,
80 pub message: String,
81 #[serde(default)]
82 pub resource: String,
83 pub request_id: String,
84 pub host_id: Option<String>,
85 pub bucket_name: Option<String>,
86 pub object_name: Option<String>,
87}
88
89impl std::fmt::Display for S3Error {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(f, "S3Error: {}", self.message)
92 }
93}
94
95impl StdError for S3Error {}
96
97impl TryFrom<&[u8]> for S3Error {
98 type Error = XmlError;
99 fn try_from(res: &[u8]) -> std::result::Result<Self, Self::Error> {
100 return Ok(crate::xml::de::from_reader(res)?);
101 }
102}
103
104impl TryFrom<&str> for S3Error {
105 type Error = XmlError;
106
107 fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
108 value.as_bytes().try_into()
109 }
110}
111
112#[derive(Debug)]
117pub enum Error {
118 ValueError(String),
120
121 RequestError(RequestError),
123
124 XmlError(XmlError),
126
127 S3Error(S3Error),
129
130 HttpError(reqwest::Error),
132
133 UnknownResponse(reqwest::Response),
135
136 MessageDecodeError(String),
138
139 SelectObejectError(String),
141
142 IoError(std::io::Error),
144}
145
146impl StdError for Error {
147 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
148 match self {
149 Error::RequestError(e) => e.source(),
150 Error::S3Error(e) => e.source(),
151 _ => None,
152 }
153 }
154}
155
156#[rustfmt::skip]
157impl fmt::Display for Error {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 match &self {
160 Error::ValueError(e) => write!(f, "{}", e),
161 Error::RequestError(e) => write!(f, "{}", e),
162 Error::XmlError(e) => write!(f, "{}", e),
163 Error::S3Error(e) => write!(f, "{}", e),
164 Error::HttpError(e) => write!(f, "{}", e),
165 Error::UnknownResponse(e) => write!(f, "Unexpected HTTP responses, status: {}", e.status()),
166 Error::MessageDecodeError(e)=> write!(f, "{}", e),
167 Error::SelectObejectError(e)=> write!(f, "{}", e),
168 Error::IoError(e) => write!(f, "{}", e),
169 }
170 }
171}
172
173impl From<S3Error> for Error {
174 fn from(err: S3Error) -> Self {
175 Error::S3Error(err)
176 }
177}
178
179impl<T: Into<ValueError>> From<T> for Error {
186 fn from(err: T) -> Self {
187 Error::ValueError(err.into().0)
188 }
189}
190
191impl From<XmlError> for Error {
192 fn from(err: XmlError) -> Self {
193 Error::XmlError(err)
194 }
195}
196
197impl From<RequestError> for Error {
198 fn from(err: RequestError) -> Self {
199 Error::RequestError(err)
200 }
201}
202
203impl From<std::io::Error> for Error {
204 fn from(err: std::io::Error) -> Self {
205 std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "");
206 Error::IoError(err)
207 }
208}
209
210impl From<reqwest::Error> for Error {
211 fn from(err: reqwest::Error) -> Self {
212 if err.is_builder() {
213 return Self::ValueError(err.to_string());
214 }
215 Self::HttpError(err)
216 }
217}
218
219impl From<reqwest::Response> for Error {
220 fn from(err: reqwest::Response) -> Self {
221 Self::UnknownResponse(err)
222 }
223}
224
225impl From<crate::xml::error::Error> for Error {
226 fn from(err: crate::xml::error::Error) -> Self {
227 Error::XmlError(err.into())
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::S3Error;
234 use crate::error::XmlError;
235
236 #[test]
237 fn test_s3_error() {
238 let res = r#"<?xml version="1.0" encoding="UTF-8"?>
239 <Error>
240 <Code>NoSuchKey</Code>
241 <Message>The resource you requested does not exist</Message>
242 <Resource>/mybucket/myfoto.jpg</Resource>
243 <RequestId>4442587FB7D0A2F9</RequestId>
244 </Error>"#;
245 let result: std::result::Result<S3Error, XmlError> = res.as_bytes().try_into();
246 assert!(result.is_ok());
247 println!("{:?}", result);
248 }
249}