1use std::error::Error as StdError;
3use std::fmt::{self, Display, Formatter};
4
5use aws_sdk::error::{ProvideErrorMetadata, SdkError};
6use aws_sdk::operation::RequestId as _;
7
8use crate::client::UploadId;
9use crate::client::part::CompletedParts;
10use crate::encoder::{EncodeError, EncodeErrorKind};
11use crate::uri::ObjectUri;
12
13pub type Result<T, E = Error> = ::std::result::Result<T, E>;
15
16#[derive(Debug, thiserror::Error)]
18pub struct Error(pub(crate) ErrorRepr);
19
20impl Error {
21 pub fn failed_upload(&self) -> Option<&FailedUpload> {
23 if let ErrorRepr::UploadFailed { failed, .. } = &self.0 {
24 return Some(failed);
25 }
26 None
27 }
28
29 pub fn kind(&self) -> ErrorKind {
31 match self.0 {
32 ErrorRepr::Sdk { .. } => ErrorKind::Sdk,
33 ErrorRepr::Missing(..) => ErrorKind::Config,
34 ErrorRepr::Encoding(..) => ErrorKind::Encoding,
35 ErrorRepr::State(_) | ErrorRepr::UploadFailed { .. } => {
36 ErrorKind::Upload
37 },
38 ErrorRepr::DynStd(_) => ErrorKind::Unknown,
39 ErrorRepr::Other { kind, .. } => kind,
40 }
41 }
42
43 pub fn from_std<E>(e: E) -> Self
45 where
46 E: StdError + Send + Sync + 'static,
47 {
48 let err = Box::new(e);
49 Self(ErrorRepr::DynStd(err))
50 }
51
52 pub fn other(kind: ErrorKind, msg: &'static str) -> Self {
54 Self(ErrorRepr::Other { kind, msg })
55 }
56
57 pub(crate) fn state(msg: &'static str) -> Self {
58 Self(ErrorRepr::State(msg))
59 }
60}
61
62impl Display for Error {
63 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
64 self.0.fmt(f)
65 }
66}
67
68impl From<ErrorRepr> for Error {
69 fn from(value: ErrorRepr) -> Self {
70 Self(value)
71 }
72}
73
74impl<E: EncodeError> From<E> for Error {
75 fn from(value: E) -> Self {
76 ErrorRepr::from(value).into()
77 }
78}
79
80impl<E> From<SdkError<E>> for Error
81where
82 E: ProvideErrorMetadata + StdError + Send + Sync + 'static,
83{
84 fn from(value: SdkError<E>) -> Self {
85 ErrorRepr::from(value).into()
86 }
87}
88
89#[derive(Debug, Clone, Copy)]
91#[non_exhaustive]
92pub enum ErrorKind {
93 Config,
95 Encoding,
97 Sdk,
99 Upload,
101 Unknown,
103}
104
105impl Display for ErrorKind {
106 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
107 match self {
108 Self::Config => write!(f, "config"),
109 Self::Encoding => write!(f, "encoding"),
110 Self::Sdk => write!(f, "sdk"),
111 Self::Upload => write!(f, "upload"),
112 Self::Unknown => write!(f, "unknown"),
113 }
114 }
115}
116
117#[derive(Debug, Clone)]
127pub struct FailedUpload {
128 pub id: UploadId,
130 pub uri: ObjectUri,
132 pub completed: CompletedParts,
134}
135
136impl FailedUpload {
137 pub(crate) fn new(
138 id: &UploadId,
139 uri: &ObjectUri,
140 completed: &CompletedParts,
141 ) -> Self {
142 Self { id: id.clone(), uri: uri.clone(), completed: completed.clone() }
143 }
144}
145
146impl Display for FailedUpload {
147 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
148 write!(
149 f,
150 r#"{{ "id": "{}", "uri": "{}", "completed": {:?} }}"#,
151 &self.id, &self.uri, &self.completed
152 )
153 }
154}
155
156pub(crate) trait ErrorWithUpload<T> {
158 fn err_with_upl(
159 self,
160 id: &UploadId,
161 uri: &ObjectUri,
162 completed: &CompletedParts,
163 ) -> Result<T>;
164}
165
166impl<T, E> ErrorWithUpload<T> for Result<T, E>
167where
168 E: StdError + Send + Sync + 'static,
169{
170 fn err_with_upl(
171 self,
172 id: &UploadId,
173 uri: &ObjectUri,
174 completed: &CompletedParts,
175 ) -> Result<T> {
176 match self {
177 Ok(t) => Ok(t),
178 Err(e) => {
179 let failed = FailedUpload::new(id, uri, completed);
180 let err =
181 ErrorRepr::UploadFailed { failed, source: Box::new(e) };
182 Err(err.into())
183 },
184 }
185 }
186}
187
188#[derive(Debug, thiserror::Error)]
190pub(crate) enum ErrorRepr {
191 #[error("{0} missing required field: {1}")]
192 Missing(&'static str, &'static str),
193 #[error("{1} error encoding value: {0}")]
194 Encoding(String, EncodeErrorKind),
195 #[error("{failed}: {source}")]
196 UploadFailed {
197 failed: FailedUpload,
198 source: Box<dyn StdError + Send + Sync>,
199 },
200 #[error("corrupted upload state: {0}")]
201 State(&'static str),
202 #[error("request {rid} returned {code}: {msg}")]
203 Sdk { code: String, msg: String, rid: String },
204 #[error("{kind} error: {msg}")]
205 Other { kind: ErrorKind, msg: &'static str },
206 #[error(transparent)]
207 DynStd(Box<dyn StdError + Send + Sync>),
208}
209
210impl<E> From<SdkError<E>> for ErrorRepr
211where
212 E: ProvideErrorMetadata + StdError + Send + Sync + 'static,
213{
214 fn from(value: SdkError<E>) -> Self {
215 let rid = value.request_id().unwrap_or("-1").to_string();
216 let code = value.code().unwrap_or_default().to_string();
217 let msg = value.message().unwrap_or_default().to_string();
218 Self::Sdk { code, msg, rid }
219 }
220}
221
222impl<E: EncodeError> From<E> for ErrorRepr {
223 fn from(value: E) -> Self {
224 ErrorRepr::Encoding(value.message(), value.kind())
225 }
226}