Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New-type all the orchestrator futures #3055

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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),
}
}

Comment on lines +39 to +48
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use the downcast trick here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it would work so well here since the Pin<Box<...>> type would need to be just right, and the chances of that are slim.

#[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
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
Loading