Skip to content

Commit

Permalink
More tidying up of aws-smithy-runtime-api (#2869)
Browse files Browse the repository at this point in the history
This PR finishes documenting `aws-smithy-runtime-api` and also:

- Adds `Send + Sync` bounds to `Interceptor`.
- Moves `Interceptors` into `aws-smithy-runtime`.
- Expands the more complicated macros in the interceptor context
wrappers.
- Makes the `OrchestratorError` an informative error according to
[RFC-22](https://github.com/awslabs/smithy-rs/blob/main/design/src/rfcs/rfc0022_error_context_and_compatibility.md).
- Renames `ConnectorError::is_other` to `as_other` and adds an
equivalent `is_other` that returns a boolean.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
  • Loading branch information
jdisanti authored Jul 25, 2023
1 parent a5465b7 commit 2922f56
Show file tree
Hide file tree
Showing 16 changed files with 793 additions and 701 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<AP> RequestChecksumInterceptor<AP> {

impl<AP> Interceptor for RequestChecksumInterceptor<AP>
where
AP: Fn(&Input) -> Result<Option<ChecksumAlgorithm>, BoxError>,
AP: Fn(&Input) -> Result<Option<ChecksumAlgorithm>, BoxError> + Send + Sync,
{
fn read_before_serialization(
&self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<VE> ResponseChecksumInterceptor<VE> {

impl<VE> Interceptor for ResponseChecksumInterceptor<VE>
where
VE: Fn(&Input) -> bool,
VE: Fn(&Input) -> bool + Send + Sync,
{
fn read_before_serialization(
&self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ where

impl<G, T> Interceptor for Route53ResourceIdInterceptor<G, T>
where
G: for<'a> Fn(&'a mut T) -> &'a mut Option<String>,
G: for<'a> Fn(&'a mut T) -> &'a mut Option<String> + Send + Sync,
T: fmt::Debug + Send + Sync + 'static,
{
fn modify_before_serialization(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class InterceptorConfigCustomization(codegenContext: ClientCodegenContext) : Con
/// ## }
/// ## }
/// ```
pub fn interceptor(mut self, interceptor: impl #{Interceptor} + Send + Sync + 'static) -> Self {
pub fn interceptor(mut self, interceptor: impl #{Interceptor} + 'static) -> Self {
self.push_interceptor(#{SharedInterceptor}::new(interceptor));
self
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class CustomizableOperationGenerator(
/// `map_request`, and `mutate_request` (the last two are implemented via interceptors under the hood).
/// The order in which those user-specified operation interceptors are invoked should not be relied upon
/// as it is an implementation detail.
pub fn interceptor(mut self, interceptor: impl #{Interceptor} + #{Send} + #{Sync} + 'static) -> Self {
pub fn interceptor(mut self, interceptor: impl #{Interceptor} + 'static) -> Self {
self.interceptors.push(#{SharedInterceptor}::new(interceptor));
self
}
Expand Down
16 changes: 13 additions & 3 deletions rust-runtime/aws-smithy-http/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,16 @@ impl DispatchFailure {
self.source.is_user()
}

/// Returns the optional error kind associated with an unclassified error
pub fn is_other(&self) -> Option<ErrorKind> {
/// Returns true if the error is an unclassified error.
pub fn is_other(&self) -> bool {
self.source.is_other()
}

/// Returns the optional error kind associated with an unclassified error
pub fn as_other(&self) -> Option<ErrorKind> {
self.source.as_other()
}

/// Returns the inner error if it is a connector error
pub fn as_connector_error(&self) -> Option<&ConnectorError> {
Some(&self.source)
Expand Down Expand Up @@ -633,8 +638,13 @@ impl ConnectorError {
matches!(self.kind, ConnectorErrorKind::User)
}

/// Returns true if the error is an unclassified error.
pub fn is_other(&self) -> bool {
matches!(self.kind, ConnectorErrorKind::Other(..))
}

/// Returns the optional error kind associated with an unclassified error
pub fn is_other(&self) -> Option<ErrorKind> {
pub fn as_other(&self) -> Option<ErrorKind> {
match &self.kind {
ConnectorErrorKind::Other(ek) => *ek,
_ => None,
Expand Down
2 changes: 1 addition & 1 deletion rust-runtime/aws-smithy-http/src/retry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl DefaultResponseRetryClassifier {
Err(SdkError::DispatchFailure(err)) => {
if err.is_timeout() || err.is_io() {
Err(RetryKind::Error(ErrorKind::TransientError))
} else if let Some(ek) = err.is_other() {
} else if let Some(ek) = err.as_other() {
Err(RetryKind::Error(ek))
} else {
Err(RetryKind::UnretryableFailure)
Expand Down
545 changes: 121 additions & 424 deletions rust-runtime/aws-smithy-runtime-api/src/client/interceptors.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ use std::{fmt, mem};
use tracing::{debug, error, trace};

// TODO(enableNewSmithyRuntimeLaunch): New-type `Input`/`Output`/`Error`
/// Type-erased operation input.
pub type Input = TypeErasedBox;
/// Type-erased operation output.
pub type Output = TypeErasedBox;
/// Type-erased operation error.
pub type Error = TypeErasedError;
/// Type-erased result for an operation.
pub type OutputOrError = Result<Output, OrchestratorError<Error>>;

type Request = HttpRequest;
Expand Down Expand Up @@ -89,38 +93,7 @@ impl InterceptorContext<Input, Output, Error> {
}
}

impl<I, O, E: Debug> InterceptorContext<I, O, E> {
/// Decomposes the context into its constituent parts.
#[doc(hidden)]
#[allow(clippy::type_complexity)]
pub fn into_parts(
self,
) -> (
Option<I>,
Option<Result<O, OrchestratorError<E>>>,
Option<Request>,
Option<Response>,
) {
(
self.input,
self.output_or_error,
self.request,
self.response,
)
}

pub fn finalize(self) -> Result<O, SdkError<E, HttpResponse>> {
let Self {
output_or_error,
response,
phase,
..
} = self;
output_or_error
.expect("output_or_error must always be set before finalize is called.")
.map_err(|error| OrchestratorError::into_sdk_error(error, &phase, response))
}

impl<I, O, E> InterceptorContext<I, O, E> {
/// Retrieve the input for the operation being invoked.
pub fn input(&self) -> Option<&I> {
self.input.as_ref()
Expand Down Expand Up @@ -188,6 +161,14 @@ impl<I, O, E: Debug> InterceptorContext<I, O, E> {
self.output_or_error.as_mut()
}

/// Return `true` if this context's `output_or_error` is an error. Otherwise, return `false`.
pub fn is_failed(&self) -> bool {
self.output_or_error
.as_ref()
.map(Result::is_err)
.unwrap_or_default()
}

/// Advance to the Serialization phase.
#[doc(hidden)]
pub fn enter_serialization_phase(&mut self) {
Expand Down Expand Up @@ -314,6 +295,44 @@ impl<I, O, E: Debug> InterceptorContext<I, O, E> {
self.output_or_error = None;
RewindResult::Occurred
}
}

impl<I, O, E> InterceptorContext<I, O, E>
where
E: Debug,
{
/// Decomposes the context into its constituent parts.
#[doc(hidden)]
#[allow(clippy::type_complexity)]
pub fn into_parts(
self,
) -> (
Option<I>,
Option<Result<O, OrchestratorError<E>>>,
Option<Request>,
Option<Response>,
) {
(
self.input,
self.output_or_error,
self.request,
self.response,
)
}

/// Convert this context into the final operation result that is returned in client's the public API.
#[doc(hidden)]
pub fn finalize(self) -> Result<O, SdkError<E, HttpResponse>> {
let Self {
output_or_error,
response,
phase,
..
} = self;
output_or_error
.expect("output_or_error must always be set before finalize is called.")
.map_err(|error| OrchestratorError::into_sdk_error(error, &phase, response))
}

/// Mark this context as failed due to errors during the operation. Any errors already contained
/// by the context will be replaced by the given error.
Expand All @@ -328,14 +347,6 @@ impl<I, O, E: Debug> InterceptorContext<I, O, E> {
error!("orchestrator context received an error but one was already present; Throwing away previous error: {:?}", existing_err);
}
}

/// Return `true` if this context's `output_or_error` is an error. Otherwise, return `false`.
pub fn is_failed(&self) -> bool {
self.output_or_error
.as_ref()
.map(Result::is_err)
.unwrap_or_default()
}
}

/// The result of attempting to rewind a request.
Expand Down
Loading

0 comments on commit 2922f56

Please sign in to comment.