Skip to content

Commit

Permalink
New-type all the orchestrator futures
Browse files Browse the repository at this point in the history
  • Loading branch information
jdisanti committed Oct 11, 2023
1 parent e06a57d commit 1ec04d1
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 118 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.next.toml
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,15 @@ For more information, see the [guide](https://github.com/awslabs/smithy-rs/discu
references = ["smithy-rs#2417", "smithy-rs#3018"]
meta = { "breaking" = true, "tada" = true, "bug" = false }
author = "Velfi"

[[aws-sdk-rust]]
message = "The future return types on traits `EndpointResolver` and `IdentityResolver` changed to new-types `EndpointFuture` and `IdentityFuture` respectively."
references = ["smithy-rs#3055"]
meta = { "breaking" = true, "tada" = true, "bug" = true }
author = "jdisanti"

[[smithy-rs]]
message = "The future return types on traits `EndpointResolver` and `IdentityResolver` changed to new-types `EndpointFuture` and `IdentityFuture` respectively."
references = ["smithy-rs#3055"]
meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "client" }
author = "jdisanti"
12 changes: 7 additions & 5 deletions aws/rust-runtime/aws-config/src/imds/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ use aws_smithy_http::result::SdkError;
use aws_smithy_runtime::client::orchestrator::operation::Operation;
use aws_smithy_runtime::client::retries::strategy::StandardRetryStrategy;
use aws_smithy_runtime_api::client::auth::AuthSchemeOptionResolverParams;
use aws_smithy_runtime_api::client::endpoint::{EndpointResolver, EndpointResolverParams};
use aws_smithy_runtime_api::client::endpoint::{
EndpointFuture, EndpointResolver, EndpointResolverParams,
};
use aws_smithy_runtime_api::client::interceptors::context::InterceptorContext;
use aws_smithy_runtime_api::client::orchestrator::{Future, OrchestratorError, SensitiveOutput};
use aws_smithy_runtime_api::client::orchestrator::{OrchestratorError, SensitiveOutput};
use aws_smithy_runtime_api::client::retries::classifiers::{
ClassifyRetry, RetryAction, SharedRetryClassifier,
};
Expand Down Expand Up @@ -522,15 +524,15 @@ struct ImdsEndpointResolver {
}

impl EndpointResolver for ImdsEndpointResolver {
fn resolve_endpoint(&self, _: &EndpointResolverParams) -> Future<Endpoint> {
fn resolve_endpoint(&self, _: &EndpointResolverParams) -> EndpointFuture {
let this = self.clone();
Future::new(Box::pin(async move {
EndpointFuture::new(async move {
this.endpoint_source
.endpoint(this.mode_override)
.await
.map(|uri| Endpoint::builder().url(uri.to_string()).build())
.map_err(|err| err.into())
}))
})
}
}

Expand Down
12 changes: 5 additions & 7 deletions aws/rust-runtime/aws-config/src/imds/client/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ use aws_smithy_runtime_api::client::auth::{
AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Signer,
};
use aws_smithy_runtime_api::client::identity::{
Identity, IdentityResolver, SharedIdentityResolver,
};
use aws_smithy_runtime_api::client::orchestrator::{
Future, HttpRequest, HttpResponse, OrchestratorError,
Identity, IdentityFuture, IdentityResolver, SharedIdentityResolver,
};
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse, OrchestratorError};
use aws_smithy_runtime_api::client::runtime_components::{
GetIdentityResolver, RuntimeComponents, RuntimeComponentsBuilder,
};
Expand Down Expand Up @@ -194,9 +192,9 @@ fn parse_token_response(response: &HttpResponse, now: SystemTime) -> Result<Toke
}

impl IdentityResolver for TokenResolver {
fn resolve_identity(&self, _config_bag: &ConfigBag) -> Future<Identity> {
fn resolve_identity(&self, _config_bag: &ConfigBag) -> IdentityFuture {
let this = self.clone();
Future::new(Box::pin(async move {
IdentityFuture::new(async move {
let preloaded_token = this
.inner
.cache
Expand All @@ -217,7 +215,7 @@ impl IdentityResolver for TokenResolver {

let expiry = token.expiry;
Ok(Identity::new(token, Some(expiry)))
}))
})
}
}

Expand Down
12 changes: 5 additions & 7 deletions aws/rust-runtime/aws-runtime/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
/// Credentials-based identity support.
pub mod credentials {
use aws_credential_types::cache::SharedCredentialsCache;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::identity::{Identity, IdentityResolver};
use aws_smithy_runtime_api::client::orchestrator::Future;
use aws_smithy_runtime_api::client::identity::{Identity, IdentityFuture, IdentityResolver};
use aws_smithy_types::config_bag::ConfigBag;

/// Smithy identity resolver for AWS credentials.
Expand All @@ -25,13 +23,13 @@ pub mod credentials {
}

impl IdentityResolver for CredentialsIdentityResolver {
fn resolve_identity(&self, _config_bag: &ConfigBag) -> Future<Identity> {
fn resolve_identity(&self, _config_bag: &ConfigBag) -> IdentityFuture {
let cache = self.credentials_cache.clone();
Future::new(Box::pin(async move {
IdentityFuture::new(async move {
let credentials = cache.as_ref().provide_cached_credentials().await?;
let expiration = credentials.expiry();
Result::<_, BoxError>::Ok(Identity::new(credentials, expiration))
}))
Ok(Identity::new(credentials, expiration))
})
}
}
}
62 changes: 62 additions & 0 deletions rust-runtime/aws-smithy-runtime-api/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,68 @@
* SPDX-License-Identifier: Apache-2.0
*/

macro_rules! new_type_future {
(
doc = $type_docs:literal,
pub struct $future_name:ident<$output:ty, $err:ty>,
) => {
pin_project_lite::pin_project! {
#[allow(clippy::type_complexity)]
#[doc = $type_docs]
pub struct $future_name {
#[pin]
inner: aws_smithy_async::future::now_or_later::NowOrLater<
Result<$output, $err>,
aws_smithy_async::future::BoxFuture<$output, $err>
>,
}
}

impl $future_name {
#[doc = concat!("Create a new `", stringify!($future_name), "` with the given future.")]
pub fn new<F>(future: F) -> Self
where
F: std::future::Future<Output = Result<$output, $err>> + Send + 'static,
{
Self {
inner: aws_smithy_async::future::now_or_later::NowOrLater::new(Box::pin(future)),
}
}

#[doc = concat!("
Create a new `", stringify!($future_name), "` with the given boxed future.
Use this if you already have a boxed future to avoid double boxing it.
")]
pub fn new_boxed(
future: std::pin::Pin<
Box<dyn std::future::Future<Output = Result<$output, $err>> + Send>,
>,
) -> Self {
Self {
inner: aws_smithy_async::future::now_or_later::NowOrLater::new(future),
}
}

#[doc = concat!("Create a `", stringify!($future_name), "` that is immediately ready with the given result.")]
pub fn ready(result: Result<$output, $err>) -> Self {
Self {
inner: aws_smithy_async::future::now_or_later::NowOrLater::ready(result),
}
}
}

impl std::future::Future for $future_name {
type Output = Result<$output, $err>;

fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
let this = self.project();
this.inner.poll(cx)
}
}
};
}

pub mod dns;

pub mod endpoint;
Expand Down
11 changes: 8 additions & 3 deletions rust-runtime/aws-smithy-runtime-api/src/client/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@

//! APIs needed to configure endpoint resolution for clients.

use crate::client::orchestrator::Future;
use crate::box_error::BoxError;
use crate::impl_shared_conversions;
use aws_smithy_types::config_bag::{Storable, StoreReplace};
use aws_smithy_types::endpoint::Endpoint;
use aws_smithy_types::type_erasure::TypeErasedBox;
use std::fmt;
use std::sync::Arc;

new_type_future! {
doc = "Future for [`EndpointResolver::resolve_endpoint`].",
pub struct EndpointFuture<Endpoint, BoxError>,
}

/// Parameters originating from the Smithy endpoint ruleset required for endpoint resolution.
///
/// The actual endpoint parameters are code generated from the Smithy model, and thus,
Expand Down Expand Up @@ -40,7 +45,7 @@ impl Storable for EndpointResolverParams {
/// Configurable endpoint resolver implementation.
pub trait EndpointResolver: Send + Sync + fmt::Debug {
/// Asynchronously resolves an endpoint to use from the given endpoint parameters.
fn resolve_endpoint(&self, params: &EndpointResolverParams) -> Future<Endpoint>;
fn resolve_endpoint(&self, params: &EndpointResolverParams) -> EndpointFuture;
}

/// Shared endpoint resolver.
Expand All @@ -57,7 +62,7 @@ impl SharedEndpointResolver {
}

impl EndpointResolver for SharedEndpointResolver {
fn resolve_endpoint(&self, params: &EndpointResolverParams) -> Future<Endpoint> {
fn resolve_endpoint(&self, params: &EndpointResolverParams) -> EndpointFuture {
self.0.resolve_endpoint(params)
}
}
Expand Down
55 changes: 3 additions & 52 deletions rust-runtime/aws-smithy-runtime-api/src/client/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,63 +56,14 @@ pub mod response;
use crate::client::orchestrator::{HttpRequest, HttpResponse};
use crate::client::runtime_components::RuntimeComponents;
use crate::impl_shared_conversions;
use aws_smithy_async::future::now_or_later::NowOrLater;
use aws_smithy_http::result::ConnectorError;
use pin_project_lite::pin_project;
use std::fmt;
use std::future::Future as StdFuture;
use std::pin::Pin;
use std::sync::Arc;
use std::task::Poll;
use std::time::Duration;

type BoxFuture = aws_smithy_async::future::BoxFuture<HttpResponse, ConnectorError>;

pin_project! {
/// Future for [`HttpConnector::call`].
pub struct HttpConnectorFuture {
#[pin]
inner: NowOrLater<Result<HttpResponse, ConnectorError>, BoxFuture>,
}
}

impl HttpConnectorFuture {
/// Create a new `HttpConnectorFuture` with the given future.
pub fn new<F>(future: F) -> Self
where
F: StdFuture<Output = Result<HttpResponse, ConnectorError>> + Send + 'static,
{
Self {
inner: NowOrLater::new(Box::pin(future)),
}
}

/// Create a new `HttpConnectorFuture` with the given boxed future.
///
/// Use this if you already have a boxed future to avoid double boxing it.
pub fn new_boxed(
future: Pin<Box<dyn StdFuture<Output = Result<HttpResponse, ConnectorError>> + Send>>,
) -> Self {
Self {
inner: NowOrLater::new(future),
}
}

/// Create a `HttpConnectorFuture` that is immediately ready with the given result.
pub fn ready(result: Result<HttpResponse, ConnectorError>) -> Self {
Self {
inner: NowOrLater::ready(result),
}
}
}

impl StdFuture for HttpConnectorFuture {
type Output = Result<HttpResponse, ConnectorError>;

fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
let this = self.project();
this.inner.poll(cx)
}
new_type_future! {
doc = "Future for [`HttpConnector::call`].",
pub struct HttpConnectorFuture<HttpResponse, ConnectorError>,
}

/// Trait with a `call` function that asynchronously converts a request into a response.
Expand Down
15 changes: 10 additions & 5 deletions rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

use crate::box_error::BoxError;
use crate::client::auth::AuthSchemeId;
use crate::client::orchestrator::Future;
use crate::impl_shared_conversions;
use aws_smithy_types::config_bag::ConfigBag;
use std::any::Any;
Expand All @@ -16,20 +16,25 @@ use std::time::SystemTime;
#[cfg(feature = "http-auth")]
pub mod http;

new_type_future! {
doc = "Future for [`IdentityResolver::resolve_identity`].",
pub struct IdentityFuture<Identity, BoxError>,
}

/// Resolver for identities.
///
/// Every [`AuthScheme`](crate::client::auth::AuthScheme) has one or more compatible
/// identity resolvers, which are selected from runtime components by the auth scheme
/// implementation itself.
///
/// The identity resolver must return a [`Future`] with the resolved identity, or an error
/// The identity resolver must return an [`IdentityFuture`] with the resolved identity, or an error
/// if resolution failed. There is no optionality for identity resolvers. The identity either
/// resolves successfully, or it fails. The orchestrator will choose exactly one auth scheme
/// to use, and thus, its chosen identity resolver is the only identity resolver that runs.
/// There is no fallback to other auth schemes in the absense of an identity.
/// There is no fallback to other auth schemes in the absence of an identity.
pub trait IdentityResolver: Send + Sync + Debug {
/// Asynchronously resolves an identity for a request using the given config.
fn resolve_identity(&self, config_bag: &ConfigBag) -> Future<Identity>;
fn resolve_identity(&self, config_bag: &ConfigBag) -> IdentityFuture;
}

/// Container for a shared identity resolver.
Expand All @@ -44,7 +49,7 @@ impl SharedIdentityResolver {
}

impl IdentityResolver for SharedIdentityResolver {
fn resolve_identity(&self, config_bag: &ConfigBag) -> Future<Identity> {
fn resolve_identity(&self, config_bag: &ConfigBag) -> IdentityFuture {
self.0.resolve_identity(config_bag)
}
}
Expand Down
11 changes: 5 additions & 6 deletions rust-runtime/aws-smithy-runtime-api/src/client/identity/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

//! Identity types for HTTP auth

use crate::client::identity::{Identity, IdentityResolver};
use crate::client::orchestrator::Future;
use crate::client::identity::{Identity, IdentityFuture, IdentityResolver};
use aws_smithy_types::config_bag::ConfigBag;
use std::fmt::Debug;
use std::sync::Arc;
Expand Down Expand Up @@ -65,8 +64,8 @@ impl From<String> for Token {
}

impl IdentityResolver for Token {
fn resolve_identity(&self, _config_bag: &ConfigBag) -> Future<Identity> {
Future::ready(Ok(Identity::new(self.clone(), self.0.expiration)))
fn resolve_identity(&self, _config_bag: &ConfigBag) -> IdentityFuture {
IdentityFuture::ready(Ok(Identity::new(self.clone(), self.0.expiration)))
}
}

Expand Down Expand Up @@ -124,7 +123,7 @@ impl Login {
}

impl IdentityResolver for Login {
fn resolve_identity(&self, _config_bag: &ConfigBag) -> Future<Identity> {
Future::ready(Ok(Identity::new(self.clone(), self.0.expiration)))
fn resolve_identity(&self, _config_bag: &ConfigBag) -> IdentityFuture {
IdentityFuture::ready(Ok(Identity::new(self.clone(), self.0.expiration)))
}
}
13 changes: 0 additions & 13 deletions rust-runtime/aws-smithy-runtime-api/src/client/orchestrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use crate::box_error::BoxError;
use crate::client::interceptors::context::phase::Phase;
use crate::client::interceptors::context::Error;
use crate::client::interceptors::InterceptorError;
use aws_smithy_async::future::now_or_later::NowOrLater;
use aws_smithy_http::body::SdkBody;
use aws_smithy_http::result::{ConnectorError, SdkError};
use aws_smithy_types::config_bag::{Storable, StoreReplace};
Expand All @@ -34,18 +33,6 @@ pub type HttpRequest = http::Request<SdkBody>;
/// Type alias for the HTTP response type that the orchestrator uses.
pub type HttpResponse = http::Response<SdkBody>;

/// Type alias for boxed futures that are returned from several traits since async trait functions are not stable yet (as of 2023-07-21).
///
/// See [the Rust blog](https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html) for
/// more information on async functions in traits.
pub type BoxFuture<T> = aws_smithy_async::future::BoxFuture<T, BoxError>;

/// Type alias for futures that are returned from several traits since async trait functions are not stable yet (as of 2023-07-21).
///
/// See [the Rust blog](https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html) for
/// more information on async functions in traits.
pub type Future<T> = NowOrLater<Result<T, BoxError>, BoxFuture<T>>;

/// Informs the orchestrator on whether or not the request body needs to be loaded into memory before transmit.
///
/// This enum gets placed into the `ConfigBag` to change the orchestrator behavior.
Expand Down
Loading

0 comments on commit 1ec04d1

Please sign in to comment.