Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into davidpz/unique-item…
Browse files Browse the repository at this point in the history
…s-validator
  • Loading branch information
david-perez committed Nov 18, 2022
2 parents e265294 + c370c8d commit 172078a
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 60 deletions.
4 changes: 3 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@
- [ ] I have updated `CHANGELOG.next.toml` if I made changes to the smithy-rs codegen or runtime crates
- [ ] I have updated `CHANGELOG.next.toml` if I made changes to the AWS SDK, generated SDK code, or SDK runtime crates

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
----

_By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata
import software.amazon.smithy.rust.codegen.core.rustlang.RustModule
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
import software.amazon.smithy.rust.codegen.core.rustlang.Visibility
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport
Expand Down Expand Up @@ -40,6 +41,12 @@ open class ServerServiceGenerator(
* which assigns a symbol location to each shape.
*/
fun render() {
rustCrate.lib {
val serviceName = codegenContext.serviceShape.id.name.toString()
rust("##[doc(inline, hidden)]")
rust("pub use crate::service::$serviceName;")
}

rustCrate.withModule(RustModule.operation(Visibility.PRIVATE)) {
ServerProtocolTestGenerator(codegenContext, protocolSupport, protocolGenerator).render(this)
}
Expand Down
55 changes: 28 additions & 27 deletions rust-runtime/aws-smithy-http-server/src/operation/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,35 +62,36 @@ where
}
}

// fn(Input, Ext0) -> Output
impl<Op, F, Fut, Ext0> Handler<Op, (Ext0,)> for F
where
Op: OperationShape,
F: Fn(Op::Input, Ext0) -> Fut,
Fut: Future,
Fut::Output: IntoResult<Op::Output, Op::Error>,
{
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;

fn call(&mut self, input: Op::Input, exts: (Ext0,)) -> Self::Future {
(self)(input, exts.0).map(IntoResult::into_result)
}
// fn(Input, Ext_i) -> Output
macro_rules! impl_handler {
($($var:ident),+) => (
impl<Op, F, Fut, $($var,)*> Handler<Op, ($($var,)*)> for F
where
Op: OperationShape,
F: Fn(Op::Input, $($var,)*) -> Fut,
Fut: Future,
Fut::Output: IntoResult<Op::Output, Op::Error>,
{
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;

fn call(&mut self, input: Op::Input, exts: ($($var,)*)) -> Self::Future {
#[allow(non_snake_case)]
let ($($var,)*) = exts;
(self)(input, $($var,)*).map(IntoResult::into_result)
}
}
)
}

// fn(Input, Ext0, Ext1) -> Output
impl<Op, F, Fut, Ext0, Ext1> Handler<Op, (Ext0, Ext1)> for F
where
Op: OperationShape,
F: Fn(Op::Input, Ext0, Ext1) -> Fut,
Fut: Future,
Fut::Output: IntoResult<Op::Output, Op::Error>,
{
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;

fn call(&mut self, input: Op::Input, exts: (Ext0, Ext1)) -> Self::Future {
(self)(input, exts.0, exts.1).map(IntoResult::into_result)
}
}
impl_handler!(Exts0);
impl_handler!(Exts0, Exts1);
impl_handler!(Exts0, Exts1, Exts2);
impl_handler!(Exts0, Exts1, Exts2, Exts3);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7, Exts8);

/// An extension trait for [`Handler`].
pub trait HandlerExt<Op, Exts>: Handler<Op, Exts>
Expand Down
61 changes: 61 additions & 0 deletions rust-runtime/aws-smithy-http-server/src/plugin/closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

use tower::layer::util::Stack;

use crate::operation::{Operation, OperationShape};

use super::Plugin;

/// An adapter to convert a `Fn(&'static str) -> Layer` closure into a [`Plugin`]. See [`plugin_from_operation_name_fn`] for more details.
pub struct OperationNameFn<F> {
f: F,
}

impl<P, Op, S, ExistingLayer, NewLayer, F> Plugin<P, Op, S, ExistingLayer> for OperationNameFn<F>
where
F: Fn(&'static str) -> NewLayer,
Op: OperationShape,
{
type Service = S;
type Layer = Stack<ExistingLayer, NewLayer>;

fn map(&self, input: Operation<S, ExistingLayer>) -> Operation<Self::Service, Self::Layer> {
input.layer((self.f)(Op::NAME))
}
}

/// Constructs a [`Plugin`] using a closure over the operation name `F: Fn(&'static str) -> L` where `L` is a HTTP
/// [`Layer`](tower::Layer).
///
/// # Example
///
/// ```rust
/// use aws_smithy_http_server::plugin::plugin_from_operation_name_fn;
/// use tower::layer::layer_fn;
///
/// // A `Service` which prints the operation name before calling `S`.
/// struct PrintService<S> {
/// operation_name: &'static str,
/// inner: S
/// }
///
/// // A `Layer` applying `PrintService`.
/// struct PrintLayer {
/// operation_name: &'static str
/// }
///
/// // Defines a closure taking the operation name to `PrintLayer`.
/// let f = |operation_name| PrintLayer { operation_name };
///
/// // This plugin applies the `PrintService` middleware around every operation.
/// let plugin = plugin_from_operation_name_fn(f);
/// ```
pub fn plugin_from_operation_name_fn<L, F>(f: F) -> OperationNameFn<F>
where
F: Fn(&'static str) -> L,
{
OperationNameFn { f }
}
25 changes: 25 additions & 0 deletions rust-runtime/aws-smithy-http-server/src/plugin/layer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

use tower::layer::util::Stack;

use crate::operation::Operation;

use super::Plugin;

/// A [`Plugin`] which appends a HTTP [`Layer`](tower::Layer) `L` to the existing `Layer` in [`Operation<S, Layer>`](Operation).
pub struct HttpLayer<L>(pub L);

impl<P, Op, S, ExistingLayer, NewLayer> Plugin<P, Op, S, ExistingLayer> for HttpLayer<NewLayer>
where
NewLayer: Clone,
{
type Service = S;
type Layer = Stack<ExistingLayer, NewLayer>;

fn map(&self, input: Operation<S, ExistingLayer>) -> Operation<Self::Service, Self::Layer> {
input.layer(self.0.clone())
}
}
4 changes: 4 additions & 0 deletions rust-runtime/aws-smithy-http-server/src/plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
* SPDX-License-Identifier: Apache-2.0
*/

mod closure;
mod filter;
mod identity;
mod layer;
mod pipeline;
mod stack;

use crate::operation::Operation;

pub use closure::{plugin_from_operation_name_fn, OperationNameFn};
pub use filter::{filter_by_operation_name, FilterByOperationName};
pub use identity::IdentityPlugin;
pub use layer::HttpLayer;
pub use pipeline::PluginPipeline;
pub use stack::PluginStack;

Expand Down
49 changes: 33 additions & 16 deletions rust-runtime/aws-smithy-http-server/src/rejection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,21 +264,38 @@ convert_to_request_rejection!(hyper::Error, HttpBody);
// Required in order to accept Lambda HTTP requests using `Router<lambda_http::Body>`.
convert_to_request_rejection!(lambda_http::Error, HttpBody);

/// A sum type rejection, implementing [`IntoResponse`] when both variants do.
pub enum EitherRejection<Left, Right> {
Left(Left),
Right(Right),
}

impl<P, L, R> IntoResponse<P> for EitherRejection<L, R>
where
L: IntoResponse<P>,
R: IntoResponse<P>,
{
fn into_response(self) -> http::Response<crate::body::BoxBody> {
match self {
EitherRejection::Left(left) => left.into_response(),
EitherRejection::Right(right) => right.into_response(),
}
pub mod any_rejections {
//! This module hosts enums, up to size 8, which implement [`IntoResponse`] when their variants implement
//! [`IntoResponse`].

use super::IntoResponse;

macro_rules! any_rejection {
($name:ident, $($var:ident),+) => (
pub enum $name<$($var),*> {
$($var ($var),)*
}

impl<P, $($var,)*> IntoResponse<P> for $name<$($var),*>
where
$($var: IntoResponse<P>,)*
{
#[allow(non_snake_case)]
fn into_response(self) -> http::Response<crate::body::BoxBody> {
match self {
$($name::$var ($var) => $var.into_response(),)*
}
}
}
)
}

// any_rejection!(One, A);
any_rejection!(Two, A, B);
any_rejection!(Three, A, B, C);
any_rejection!(Four, A, B, C, D);
any_rejection!(Five, A, B, C, D, E);
any_rejection!(Six, A, B, C, D, E, F);
any_rejection!(Seven, A, B, C, D, E, F, G);
any_rejection!(Eight, A, B, C, D, E, F, G, H);
}
44 changes: 28 additions & 16 deletions rust-runtime/aws-smithy-http-server/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use futures_util::{
};
use http::{request::Parts, Extensions, HeaderMap, Request, Uri};

use crate::{rejection::EitherRejection, response::IntoResponse};
use crate::{rejection::any_rejections, response::IntoResponse};

#[doc(hidden)]
#[derive(Debug)]
Expand Down Expand Up @@ -139,20 +139,32 @@ where
}
}

impl<P, T1, T2> FromParts<P> for (T1, T2)
where
T1: FromParts<P>,
T2: FromParts<P>,
{
type Rejection = EitherRejection<T1::Rejection, T2::Rejection>;

fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
let t1 = T1::from_parts(parts).map_err(EitherRejection::Left)?;
let t2 = T2::from_parts(parts).map_err(EitherRejection::Right)?;
Ok((t1, t2))
}
macro_rules! impl_from_parts {
($error_name:ident, $($var:ident),+) => (
impl<P, $($var,)*> FromParts<P> for ($($var),*)
where
$($var: FromParts<P>,)*
{
type Rejection = any_rejections::$error_name<$($var::Rejection),*>;

fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
let tuple = (
$($var::from_parts(parts).map_err(any_rejections::$error_name::$var)?,)*
);
Ok(tuple)
}
}
)
}

impl_from_parts!(Two, A, B);
impl_from_parts!(Three, A, B, C);
impl_from_parts!(Four, A, B, C, D);
impl_from_parts!(Five, A, B, C, D, E);
impl_from_parts!(Six, A, B, C, D, E, F);
impl_from_parts!(Seven, A, B, C, D, E, F, G);
impl_from_parts!(Eight, A, B, C, D, E, F, G, H);

/// Provides a protocol aware extraction from a [`Request`]. This consumes the
/// [`Request`], in contrast to [`FromParts`].
pub trait FromRequest<Protocol, B>: Sized {
Expand Down Expand Up @@ -180,14 +192,14 @@ where
T1: FromRequest<P, B>,
T2: FromParts<P>,
{
type Rejection = EitherRejection<T1::Rejection, T2::Rejection>;
type Rejection = any_rejections::Two<T1::Rejection, T2::Rejection>;
type Future = TryJoin<MapErr<T1::Future, fn(T1::Rejection) -> Self::Rejection>, Ready<Result<T2, Self::Rejection>>>;

fn from_request(request: Request<B>) -> Self::Future {
let (mut parts, body) = request.into_parts();
let t2_result = T2::from_parts(&mut parts).map_err(EitherRejection::Right);
let t2_result = T2::from_parts(&mut parts).map_err(any_rejections::Two::B);
try_join(
T1::from_request(Request::from_parts(parts, body)).map_err(EitherRejection::Left),
T1::from_request(Request::from_parts(parts, body)).map_err(any_rejections::Two::A),
ready(t2_result),
)
}
Expand Down

0 comments on commit 172078a

Please sign in to comment.