#![warn(
missing_debug_implementations,
missing_docs,
rustdoc::all,
unreachable_pub
)]
use crate::operation;
use aws_smithy_types::retry::ErrorKind;
use std::error::Error;
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
type BoxError = Box<dyn Error + Send + Sync>;
#[derive(Debug)]
pub struct SdkSuccess<O> {
pub raw: operation::Response,
pub parsed: O,
}
#[derive(Debug)]
pub struct ConstructionFailure {
source: BoxError,
}
#[derive(Debug)]
pub struct TimeoutError {
source: BoxError,
}
#[derive(Debug)]
pub struct DispatchFailure {
source: ConnectorError,
}
impl DispatchFailure {
pub fn is_io(&self) -> bool {
self.source.is_io()
}
pub fn is_timeout(&self) -> bool {
self.source.is_timeout()
}
pub fn is_user(&self) -> bool {
self.source.is_user()
}
pub fn is_other(&self) -> Option<ErrorKind> {
self.source.is_other()
}
}
#[derive(Debug)]
pub struct ResponseError<R> {
source: BoxError,
raw: R,
}
impl<R> ResponseError<R> {
pub fn raw(&self) -> &R {
&self.raw
}
pub fn into_raw(self) -> R {
self.raw
}
}
#[derive(Debug)]
pub struct ServiceError<E, R> {
source: E,
raw: R,
}
impl<E, R> ServiceError<E, R> {
pub fn err(&self) -> &E {
&self.source
}
pub fn into_err(self) -> E {
self.source
}
pub fn raw(&self) -> &R {
&self.raw
}
pub fn into_raw(self) -> R {
self.raw
}
}
pub trait CreateUnhandledError {
fn create_unhandled_error(source: Box<dyn Error + Send + Sync + 'static>) -> Self;
}
#[non_exhaustive]
#[derive(Debug)]
pub enum SdkError<E, R = operation::Response> {
ConstructionFailure(ConstructionFailure),
TimeoutError(TimeoutError),
DispatchFailure(DispatchFailure),
ResponseError(ResponseError<R>),
ServiceError(ServiceError<E, R>),
}
impl<E, R> SdkError<E, R> {
pub fn construction_failure(source: impl Into<BoxError>) -> Self {
Self::ConstructionFailure(ConstructionFailure {
source: source.into(),
})
}
pub fn timeout_error(source: impl Into<BoxError>) -> Self {
Self::TimeoutError(TimeoutError {
source: source.into(),
})
}
pub fn dispatch_failure(source: ConnectorError) -> Self {
Self::DispatchFailure(DispatchFailure { source })
}
pub fn response_error(source: impl Into<BoxError>, raw: R) -> Self {
Self::ResponseError(ResponseError {
source: source.into(),
raw,
})
}
pub fn service_error(source: E, raw: R) -> Self {
Self::ServiceError(ServiceError { source, raw })
}
pub fn into_service_error(self) -> E
where
E: std::error::Error + Send + Sync + CreateUnhandledError + 'static,
R: Debug + Send + Sync + 'static,
{
match self {
Self::ServiceError(context) => context.source,
_ => E::create_unhandled_error(self.into()),
}
}
pub fn into_source(self) -> Result<Box<dyn Error + Send + Sync + 'static>, Self>
where
E: std::error::Error + Send + Sync + 'static,
{
use SdkError::*;
match self {
ConstructionFailure(context) => Ok(context.source),
TimeoutError(context) => Ok(context.source),
ResponseError(context) => Ok(context.source),
DispatchFailure(context) => Ok(context.source.into()),
ServiceError(context) => Ok(context.source.into()),
}
}
}
impl<E, R> Display for SdkError<E, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
SdkError::ConstructionFailure(_) => write!(f, "failed to construct request"),
SdkError::TimeoutError(_) => write!(f, "request has timed out"),
SdkError::DispatchFailure(_) => write!(f, "dispatch failure"),
SdkError::ResponseError(_) => write!(f, "response error"),
SdkError::ServiceError(_) => write!(f, "service error"),
}
}
}
impl<E, R> Error for SdkError<E, R>
where
E: Error + 'static,
R: Debug,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
use SdkError::*;
match self {
ConstructionFailure(context) => Some(context.source.as_ref()),
TimeoutError(context) => Some(context.source.as_ref()),
ResponseError(context) => Some(context.source.as_ref()),
DispatchFailure(context) => Some(&context.source),
ServiceError(context) => Some(&context.source),
}
}
}
#[derive(Debug)]
enum ConnectorErrorKind {
Timeout,
User,
Io,
Other(Option<ErrorKind>),
}
#[derive(Debug)]
pub struct ConnectorError {
kind: ConnectorErrorKind,
source: BoxError,
}
impl Display for ConnectorError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.kind {
ConnectorErrorKind::Timeout => write!(f, "timeout"),
ConnectorErrorKind::User => write!(f, "user error"),
ConnectorErrorKind::Io => write!(f, "io error"),
ConnectorErrorKind::Other(_) => write!(f, "other"),
}
}
}
impl Error for ConnectorError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(self.source.as_ref())
}
}
impl ConnectorError {
pub fn timeout(source: BoxError) -> Self {
Self {
kind: ConnectorErrorKind::Timeout,
source,
}
}
pub fn user(source: BoxError) -> Self {
Self {
kind: ConnectorErrorKind::User,
source,
}
}
pub fn io(source: BoxError) -> Self {
Self {
kind: ConnectorErrorKind::Io,
source,
}
}
pub fn other(source: BoxError, kind: Option<ErrorKind>) -> Self {
Self {
source,
kind: ConnectorErrorKind::Other(kind),
}
}
pub fn is_io(&self) -> bool {
matches!(self.kind, ConnectorErrorKind::Io)
}
pub fn is_timeout(&self) -> bool {
matches!(self.kind, ConnectorErrorKind::Timeout)
}
pub fn is_user(&self) -> bool {
matches!(self.kind, ConnectorErrorKind::User)
}
pub fn is_other(&self) -> Option<ErrorKind> {
match &self.kind {
ConnectorErrorKind::Other(ek) => *ek,
_ => None,
}
}
}