1use crate::client::connection::ConnectionMetadata;
9use aws_smithy_types::error::metadata::{ProvideErrorMetadata, EMPTY_ERROR_METADATA};
10use aws_smithy_types::error::operation::BuildError;
11use aws_smithy_types::error::ErrorMetadata;
12use aws_smithy_types::retry::ErrorKind;
13use std::error::Error;
14use std::fmt;
15use std::fmt::{Debug, Display, Formatter};
16
17type BoxError = Box<dyn Error + Send + Sync>;
18
19pub mod builders {
21    use super::*;
22
23    macro_rules! source_only_error_builder {
24        ($errorName:ident, $builderName:ident, $sourceType:ident) => {
25            #[doc = concat!("Builder for [`", stringify!($errorName), "`](super::", stringify!($errorName), ").")]
26            #[derive(Debug, Default)]
27            pub struct $builderName {
28                source: Option<$sourceType>,
29            }
30
31            impl $builderName {
32                #[doc = "Creates a new builder."]
33                pub fn new() -> Self { Default::default() }
34
35                #[doc = "Sets the error source."]
36                pub fn source(mut self, source: impl Into<$sourceType>) -> Self {
37                    self.source = Some(source.into());
38                    self
39                }
40
41                #[doc = "Sets the error source."]
42                pub fn set_source(&mut self, source: Option<$sourceType>) -> &mut Self {
43                    self.source = source;
44                    self
45                }
46
47                #[doc = "Builds the error context."]
48                pub fn build(self) -> $errorName {
49                    $errorName { source: self.source.expect("source is required") }
50                }
51            }
52        };
53    }
54
55    source_only_error_builder!(ConstructionFailure, ConstructionFailureBuilder, BoxError);
56    source_only_error_builder!(TimeoutError, TimeoutErrorBuilder, BoxError);
57    source_only_error_builder!(DispatchFailure, DispatchFailureBuilder, ConnectorError);
58
59    #[derive(Debug)]
61    pub struct ResponseErrorBuilder<R> {
62        source: Option<BoxError>,
63        raw: Option<R>,
64    }
65
66    impl<R> Default for ResponseErrorBuilder<R> {
67        fn default() -> Self {
68            Self {
69                source: None,
70                raw: None,
71            }
72        }
73    }
74
75    impl<R> ResponseErrorBuilder<R> {
76        pub fn new() -> Self {
78            Default::default()
79        }
80
81        pub fn source(mut self, source: impl Into<BoxError>) -> Self {
83            self.source = Some(source.into());
84            self
85        }
86
87        pub fn set_source(&mut self, source: Option<BoxError>) -> &mut Self {
89            self.source = source;
90            self
91        }
92
93        pub fn raw(mut self, raw: R) -> Self {
95            self.raw = Some(raw);
96            self
97        }
98
99        pub fn set_raw(&mut self, raw: Option<R>) -> &mut Self {
101            self.raw = raw;
102            self
103        }
104
105        pub fn build(self) -> ResponseError<R> {
107            ResponseError {
108                source: self.source.expect("source is required"),
109                raw: self.raw.expect("a raw response is required"),
110            }
111        }
112    }
113
114    #[derive(Debug)]
116    pub struct ServiceErrorBuilder<E, R> {
117        source: Option<E>,
118        raw: Option<R>,
119    }
120
121    impl<E, R> Default for ServiceErrorBuilder<E, R> {
122        fn default() -> Self {
123            Self {
124                source: None,
125                raw: None,
126            }
127        }
128    }
129
130    impl<E, R> ServiceErrorBuilder<E, R> {
131        pub fn new() -> Self {
133            Default::default()
134        }
135
136        pub fn source(mut self, source: impl Into<E>) -> Self {
138            self.source = Some(source.into());
139            self
140        }
141
142        pub fn set_source(&mut self, source: Option<E>) -> &mut Self {
144            self.source = source;
145            self
146        }
147
148        pub fn raw(mut self, raw: R) -> Self {
150            self.raw = Some(raw);
151            self
152        }
153
154        pub fn set_raw(&mut self, raw: Option<R>) -> &mut Self {
156            self.raw = raw;
157            self
158        }
159
160        pub fn build(self) -> ServiceError<E, R> {
162            ServiceError {
163                source: self.source.expect("source is required"),
164                raw: self.raw.expect("a raw response is required"),
165            }
166        }
167    }
168}
169
170#[derive(Debug)]
172pub struct ConstructionFailure {
173    pub(crate) source: BoxError,
174}
175
176impl ConstructionFailure {
177    pub fn builder() -> builders::ConstructionFailureBuilder {
179        builders::ConstructionFailureBuilder::new()
180    }
181}
182
183#[derive(Debug)]
185pub struct TimeoutError {
186    source: BoxError,
187}
188
189impl TimeoutError {
190    pub fn builder() -> builders::TimeoutErrorBuilder {
192        builders::TimeoutErrorBuilder::new()
193    }
194}
195
196#[derive(Debug)]
198pub struct DispatchFailure {
199    source: ConnectorError,
200}
201
202impl DispatchFailure {
203    pub fn builder() -> builders::DispatchFailureBuilder {
205        builders::DispatchFailureBuilder::new()
206    }
207
208    pub fn is_io(&self) -> bool {
210        self.source.is_io()
211    }
212
213    pub fn is_timeout(&self) -> bool {
215        self.source.is_timeout()
216    }
217
218    pub fn is_user(&self) -> bool {
220        self.source.is_user()
221    }
222
223    pub fn is_other(&self) -> bool {
225        self.source.is_other()
226    }
227
228    pub fn as_other(&self) -> Option<ErrorKind> {
230        self.source.as_other()
231    }
232
233    pub fn as_connector_error(&self) -> Option<&ConnectorError> {
235        Some(&self.source)
236    }
237}
238
239#[derive(Debug)]
241pub struct ResponseError<R> {
242    source: BoxError,
244    raw: R,
246}
247
248impl<R> ResponseError<R> {
249    pub fn builder() -> builders::ResponseErrorBuilder<R> {
251        builders::ResponseErrorBuilder::new()
252    }
253
254    pub fn raw(&self) -> &R {
256        &self.raw
257    }
258
259    pub fn into_raw(self) -> R {
261        self.raw
262    }
263}
264
265#[derive(Debug)]
267pub struct ServiceError<E, R> {
268    source: E,
270    raw: R,
272}
273
274impl<E, R> ServiceError<E, R> {
275    pub fn builder() -> builders::ServiceErrorBuilder<E, R> {
277        builders::ServiceErrorBuilder::new()
278    }
279
280    pub fn err(&self) -> &E {
282        &self.source
283    }
284
285    pub fn into_err(self) -> E {
287        self.source
288    }
289
290    pub fn raw(&self) -> &R {
292        &self.raw
293    }
294
295    pub fn into_raw(self) -> R {
297        self.raw
298    }
299}
300
301pub trait CreateUnhandledError {
305    fn create_unhandled_error(
307        source: Box<dyn Error + Send + Sync + 'static>,
308        meta: Option<ErrorMetadata>,
309    ) -> Self;
310}
311
312#[non_exhaustive]
319#[derive(Debug)]
320pub enum SdkError<E, R> {
321    ConstructionFailure(ConstructionFailure),
323
324    TimeoutError(TimeoutError),
326
327    DispatchFailure(DispatchFailure),
330
331    ResponseError(ResponseError<R>),
334
335    ServiceError(ServiceError<E, R>),
337}
338
339impl<E, R> SdkError<E, R> {
340    pub fn construction_failure(source: impl Into<BoxError>) -> Self {
342        Self::ConstructionFailure(ConstructionFailure {
343            source: source.into(),
344        })
345    }
346
347    pub fn timeout_error(source: impl Into<BoxError>) -> Self {
349        Self::TimeoutError(TimeoutError {
350            source: source.into(),
351        })
352    }
353
354    pub fn dispatch_failure(source: ConnectorError) -> Self {
356        Self::DispatchFailure(DispatchFailure { source })
357    }
358
359    pub fn response_error(source: impl Into<BoxError>, raw: R) -> Self {
361        Self::ResponseError(ResponseError {
362            source: source.into(),
363            raw,
364        })
365    }
366
367    pub fn service_error(source: E, raw: R) -> Self {
369        Self::ServiceError(ServiceError { source, raw })
370    }
371
372    pub fn into_service_error(self) -> E
405    where
406        E: std::error::Error + Send + Sync + CreateUnhandledError + 'static,
407        R: Debug + Send + Sync + 'static,
408    {
409        match self {
410            Self::ServiceError(context) => context.source,
411            _ => E::create_unhandled_error(self.into(), None),
412        }
413    }
414
415    pub fn as_service_error(&self) -> Option<&E> {
439        match self {
440            Self::ServiceError(err) => Some(&err.source),
441            _ => None,
442        }
443    }
444
445    pub fn into_source(self) -> Result<Box<dyn Error + Send + Sync + 'static>, Self>
449    where
450        E: std::error::Error + Send + Sync + 'static,
451    {
452        match self {
453            SdkError::ConstructionFailure(context) => Ok(context.source),
454            SdkError::TimeoutError(context) => Ok(context.source),
455            SdkError::ResponseError(context) => Ok(context.source),
456            SdkError::DispatchFailure(context) => Ok(context.source.into()),
457            SdkError::ServiceError(context) => Ok(context.source.into()),
458        }
459    }
460
461    pub fn raw_response(&self) -> Option<&R> {
463        match self {
464            SdkError::ServiceError(inner) => Some(inner.raw()),
465            SdkError::ResponseError(inner) => Some(inner.raw()),
466            _ => None,
467        }
468    }
469
470    pub fn map_service_error<E2>(self, map: impl FnOnce(E) -> E2) -> SdkError<E2, R> {
472        match self {
473            SdkError::ServiceError(context) => SdkError::<E2, R>::ServiceError(ServiceError {
474                source: map(context.source),
475                raw: context.raw,
476            }),
477            SdkError::ConstructionFailure(context) => {
478                SdkError::<E2, R>::ConstructionFailure(context)
479            }
480            SdkError::DispatchFailure(context) => SdkError::<E2, R>::DispatchFailure(context),
481            SdkError::ResponseError(context) => SdkError::<E2, R>::ResponseError(context),
482            SdkError::TimeoutError(context) => SdkError::<E2, R>::TimeoutError(context),
483        }
484    }
485}
486
487impl<E, R> Display for SdkError<E, R> {
488    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
489        match self {
490            SdkError::ConstructionFailure(_) => write!(f, "failed to construct request"),
491            SdkError::TimeoutError(_) => write!(f, "request has timed out"),
492            SdkError::DispatchFailure(_) => write!(f, "dispatch failure"),
493            SdkError::ResponseError(_) => write!(f, "response error"),
494            SdkError::ServiceError(_) => write!(f, "service error"),
495        }
496    }
497}
498
499impl<E, R> Error for SdkError<E, R>
500where
501    E: Error + 'static,
502    R: Debug,
503{
504    fn source(&self) -> Option<&(dyn Error + 'static)> {
505        match self {
506            SdkError::ConstructionFailure(context) => Some(context.source.as_ref()),
507            SdkError::TimeoutError(context) => Some(context.source.as_ref()),
508            SdkError::ResponseError(context) => Some(context.source.as_ref()),
509            SdkError::DispatchFailure(context) => Some(&context.source),
510            SdkError::ServiceError(context) => Some(&context.source),
511        }
512    }
513}
514
515impl<E, R> From<BuildError> for SdkError<E, R> {
516    fn from(value: BuildError) -> Self {
517        SdkError::ConstructionFailure(ConstructionFailure::builder().source(value).build())
518    }
519}
520
521impl<E, R> ProvideErrorMetadata for SdkError<E, R>
522where
523    E: ProvideErrorMetadata,
524{
525    fn meta(&self) -> &aws_smithy_types::error::ErrorMetadata {
526        match self {
527            SdkError::ConstructionFailure(_) => &EMPTY_ERROR_METADATA,
528            SdkError::TimeoutError(_) => &EMPTY_ERROR_METADATA,
529            SdkError::DispatchFailure(_) => &EMPTY_ERROR_METADATA,
530            SdkError::ResponseError(_) => &EMPTY_ERROR_METADATA,
531            SdkError::ServiceError(err) => err.source.meta(),
532        }
533    }
534}
535
536#[derive(Debug)]
537enum ConnectorErrorKind {
538    Timeout,
540
541    User,
543
544    Io,
546
547    Other(Option<ErrorKind>),
549}
550
551#[derive(Debug)]
558pub struct ConnectorError {
559    kind: ConnectorErrorKind,
560    source: BoxError,
561    connection: ConnectionStatus,
562}
563
564#[non_exhaustive]
565#[derive(Debug)]
566pub(crate) enum ConnectionStatus {
567    NeverConnected,
571
572    Unknown,
574
575    Connected(ConnectionMetadata),
577}
578
579impl Display for ConnectorError {
580    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
581        match self.kind {
582            ConnectorErrorKind::Timeout => write!(f, "timeout"),
583            ConnectorErrorKind::User => write!(f, "user error"),
584            ConnectorErrorKind::Io => write!(f, "io error"),
585            ConnectorErrorKind::Other(_) => write!(f, "other"),
586        }
587    }
588}
589
590impl Error for ConnectorError {
591    fn source(&self) -> Option<&(dyn Error + 'static)> {
592        Some(self.source.as_ref())
593    }
594}
595
596impl ConnectorError {
597    pub fn timeout(source: BoxError) -> Self {
601        Self {
602            kind: ConnectorErrorKind::Timeout,
603            source,
604            connection: ConnectionStatus::Unknown,
605        }
606    }
607
608    pub fn with_connection(mut self, info: ConnectionMetadata) -> Self {
610        self.connection = ConnectionStatus::Connected(info);
611        self
612    }
613
614    pub fn never_connected(mut self) -> Self {
616        self.connection = ConnectionStatus::NeverConnected;
617        self
618    }
619
620    pub fn user(source: BoxError) -> Self {
622        Self {
623            kind: ConnectorErrorKind::User,
624            source,
625            connection: ConnectionStatus::Unknown,
626        }
627    }
628
629    pub fn io(source: BoxError) -> Self {
631        Self {
632            kind: ConnectorErrorKind::Io,
633            source,
634            connection: ConnectionStatus::Unknown,
635        }
636    }
637
638    pub fn other(source: BoxError, kind: Option<ErrorKind>) -> Self {
642        Self {
643            source,
644            kind: ConnectorErrorKind::Other(kind),
645            connection: ConnectionStatus::Unknown,
646        }
647    }
648
649    pub fn is_io(&self) -> bool {
651        matches!(self.kind, ConnectorErrorKind::Io)
652    }
653
654    pub fn is_timeout(&self) -> bool {
656        matches!(self.kind, ConnectorErrorKind::Timeout)
657    }
658
659    pub fn is_user(&self) -> bool {
661        matches!(self.kind, ConnectorErrorKind::User)
662    }
663
664    pub fn is_other(&self) -> bool {
666        matches!(self.kind, ConnectorErrorKind::Other(..))
667    }
668
669    pub fn as_other(&self) -> Option<ErrorKind> {
671        match &self.kind {
672            ConnectorErrorKind::Other(ek) => *ek,
673            _ => None,
674        }
675    }
676
677    pub fn into_source(self) -> BoxError {
679        self.source
680    }
681
682    pub fn connection_metadata(&self) -> Option<&ConnectionMetadata> {
687        match &self.connection {
688            ConnectionStatus::NeverConnected => None,
689            ConnectionStatus::Unknown => None,
690            ConnectionStatus::Connected(conn) => Some(conn),
691        }
692    }
693}