Skip to content

Commit 172078a

Browse files
committed
Merge remote-tracking branch 'upstream/main' into davidpz/unique-items-validator
2 parents e265294 + c370c8d commit 172078a

File tree

8 files changed

+189
-60
lines changed

8 files changed

+189
-60
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@
1515
- [ ] I have updated `CHANGELOG.next.toml` if I made changes to the smithy-rs codegen or runtime crates
1616
- [ ] I have updated `CHANGELOG.next.toml` if I made changes to the AWS SDK, generated SDK code, or SDK runtime crates
1717

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

codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata
1212
import software.amazon.smithy.rust.codegen.core.rustlang.RustModule
1313
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
1414
import software.amazon.smithy.rust.codegen.core.rustlang.Visibility
15+
import software.amazon.smithy.rust.codegen.core.rustlang.rust
1516
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
1617
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
1718
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport
@@ -40,6 +41,12 @@ open class ServerServiceGenerator(
4041
* which assigns a symbol location to each shape.
4142
*/
4243
fun render() {
44+
rustCrate.lib {
45+
val serviceName = codegenContext.serviceShape.id.name.toString()
46+
rust("##[doc(inline, hidden)]")
47+
rust("pub use crate::service::$serviceName;")
48+
}
49+
4350
rustCrate.withModule(RustModule.operation(Visibility.PRIVATE)) {
4451
ServerProtocolTestGenerator(codegenContext, protocolSupport, protocolGenerator).render(this)
4552
}

rust-runtime/aws-smithy-http-server/src/operation/handler.rs

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -62,35 +62,36 @@ where
6262
}
6363
}
6464

65-
// fn(Input, Ext0) -> Output
66-
impl<Op, F, Fut, Ext0> Handler<Op, (Ext0,)> for F
67-
where
68-
Op: OperationShape,
69-
F: Fn(Op::Input, Ext0) -> Fut,
70-
Fut: Future,
71-
Fut::Output: IntoResult<Op::Output, Op::Error>,
72-
{
73-
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;
74-
75-
fn call(&mut self, input: Op::Input, exts: (Ext0,)) -> Self::Future {
76-
(self)(input, exts.0).map(IntoResult::into_result)
77-
}
65+
// fn(Input, Ext_i) -> Output
66+
macro_rules! impl_handler {
67+
($($var:ident),+) => (
68+
impl<Op, F, Fut, $($var,)*> Handler<Op, ($($var,)*)> for F
69+
where
70+
Op: OperationShape,
71+
F: Fn(Op::Input, $($var,)*) -> Fut,
72+
Fut: Future,
73+
Fut::Output: IntoResult<Op::Output, Op::Error>,
74+
{
75+
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;
76+
77+
fn call(&mut self, input: Op::Input, exts: ($($var,)*)) -> Self::Future {
78+
#[allow(non_snake_case)]
79+
let ($($var,)*) = exts;
80+
(self)(input, $($var,)*).map(IntoResult::into_result)
81+
}
82+
}
83+
)
7884
}
7985

80-
// fn(Input, Ext0, Ext1) -> Output
81-
impl<Op, F, Fut, Ext0, Ext1> Handler<Op, (Ext0, Ext1)> for F
82-
where
83-
Op: OperationShape,
84-
F: Fn(Op::Input, Ext0, Ext1) -> Fut,
85-
Fut: Future,
86-
Fut::Output: IntoResult<Op::Output, Op::Error>,
87-
{
88-
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;
89-
90-
fn call(&mut self, input: Op::Input, exts: (Ext0, Ext1)) -> Self::Future {
91-
(self)(input, exts.0, exts.1).map(IntoResult::into_result)
92-
}
93-
}
86+
impl_handler!(Exts0);
87+
impl_handler!(Exts0, Exts1);
88+
impl_handler!(Exts0, Exts1, Exts2);
89+
impl_handler!(Exts0, Exts1, Exts2, Exts3);
90+
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4);
91+
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5);
92+
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6);
93+
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7);
94+
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7, Exts8);
9495

9596
/// An extension trait for [`Handler`].
9697
pub trait HandlerExt<Op, Exts>: Handler<Op, Exts>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
use tower::layer::util::Stack;
7+
8+
use crate::operation::{Operation, OperationShape};
9+
10+
use super::Plugin;
11+
12+
/// An adapter to convert a `Fn(&'static str) -> Layer` closure into a [`Plugin`]. See [`plugin_from_operation_name_fn`] for more details.
13+
pub struct OperationNameFn<F> {
14+
f: F,
15+
}
16+
17+
impl<P, Op, S, ExistingLayer, NewLayer, F> Plugin<P, Op, S, ExistingLayer> for OperationNameFn<F>
18+
where
19+
F: Fn(&'static str) -> NewLayer,
20+
Op: OperationShape,
21+
{
22+
type Service = S;
23+
type Layer = Stack<ExistingLayer, NewLayer>;
24+
25+
fn map(&self, input: Operation<S, ExistingLayer>) -> Operation<Self::Service, Self::Layer> {
26+
input.layer((self.f)(Op::NAME))
27+
}
28+
}
29+
30+
/// Constructs a [`Plugin`] using a closure over the operation name `F: Fn(&'static str) -> L` where `L` is a HTTP
31+
/// [`Layer`](tower::Layer).
32+
///
33+
/// # Example
34+
///
35+
/// ```rust
36+
/// use aws_smithy_http_server::plugin::plugin_from_operation_name_fn;
37+
/// use tower::layer::layer_fn;
38+
///
39+
/// // A `Service` which prints the operation name before calling `S`.
40+
/// struct PrintService<S> {
41+
/// operation_name: &'static str,
42+
/// inner: S
43+
/// }
44+
///
45+
/// // A `Layer` applying `PrintService`.
46+
/// struct PrintLayer {
47+
/// operation_name: &'static str
48+
/// }
49+
///
50+
/// // Defines a closure taking the operation name to `PrintLayer`.
51+
/// let f = |operation_name| PrintLayer { operation_name };
52+
///
53+
/// // This plugin applies the `PrintService` middleware around every operation.
54+
/// let plugin = plugin_from_operation_name_fn(f);
55+
/// ```
56+
pub fn plugin_from_operation_name_fn<L, F>(f: F) -> OperationNameFn<F>
57+
where
58+
F: Fn(&'static str) -> L,
59+
{
60+
OperationNameFn { f }
61+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
use tower::layer::util::Stack;
7+
8+
use crate::operation::Operation;
9+
10+
use super::Plugin;
11+
12+
/// A [`Plugin`] which appends a HTTP [`Layer`](tower::Layer) `L` to the existing `Layer` in [`Operation<S, Layer>`](Operation).
13+
pub struct HttpLayer<L>(pub L);
14+
15+
impl<P, Op, S, ExistingLayer, NewLayer> Plugin<P, Op, S, ExistingLayer> for HttpLayer<NewLayer>
16+
where
17+
NewLayer: Clone,
18+
{
19+
type Service = S;
20+
type Layer = Stack<ExistingLayer, NewLayer>;
21+
22+
fn map(&self, input: Operation<S, ExistingLayer>) -> Operation<Self::Service, Self::Layer> {
23+
input.layer(self.0.clone())
24+
}
25+
}

rust-runtime/aws-smithy-http-server/src/plugin/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
mod closure;
67
mod filter;
78
mod identity;
9+
mod layer;
810
mod pipeline;
911
mod stack;
1012

1113
use crate::operation::Operation;
1214

15+
pub use closure::{plugin_from_operation_name_fn, OperationNameFn};
1316
pub use filter::{filter_by_operation_name, FilterByOperationName};
1417
pub use identity::IdentityPlugin;
18+
pub use layer::HttpLayer;
1519
pub use pipeline::PluginPipeline;
1620
pub use stack::PluginStack;
1721

rust-runtime/aws-smithy-http-server/src/rejection.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -264,21 +264,38 @@ convert_to_request_rejection!(hyper::Error, HttpBody);
264264
// Required in order to accept Lambda HTTP requests using `Router<lambda_http::Body>`.
265265
convert_to_request_rejection!(lambda_http::Error, HttpBody);
266266

267-
/// A sum type rejection, implementing [`IntoResponse`] when both variants do.
268-
pub enum EitherRejection<Left, Right> {
269-
Left(Left),
270-
Right(Right),
271-
}
272-
273-
impl<P, L, R> IntoResponse<P> for EitherRejection<L, R>
274-
where
275-
L: IntoResponse<P>,
276-
R: IntoResponse<P>,
277-
{
278-
fn into_response(self) -> http::Response<crate::body::BoxBody> {
279-
match self {
280-
EitherRejection::Left(left) => left.into_response(),
281-
EitherRejection::Right(right) => right.into_response(),
282-
}
267+
pub mod any_rejections {
268+
//! This module hosts enums, up to size 8, which implement [`IntoResponse`] when their variants implement
269+
//! [`IntoResponse`].
270+
271+
use super::IntoResponse;
272+
273+
macro_rules! any_rejection {
274+
($name:ident, $($var:ident),+) => (
275+
pub enum $name<$($var),*> {
276+
$($var ($var),)*
277+
}
278+
279+
impl<P, $($var,)*> IntoResponse<P> for $name<$($var),*>
280+
where
281+
$($var: IntoResponse<P>,)*
282+
{
283+
#[allow(non_snake_case)]
284+
fn into_response(self) -> http::Response<crate::body::BoxBody> {
285+
match self {
286+
$($name::$var ($var) => $var.into_response(),)*
287+
}
288+
}
289+
}
290+
)
283291
}
292+
293+
// any_rejection!(One, A);
294+
any_rejection!(Two, A, B);
295+
any_rejection!(Three, A, B, C);
296+
any_rejection!(Four, A, B, C, D);
297+
any_rejection!(Five, A, B, C, D, E);
298+
any_rejection!(Six, A, B, C, D, E, F);
299+
any_rejection!(Seven, A, B, C, D, E, F, G);
300+
any_rejection!(Eight, A, B, C, D, E, F, G, H);
284301
}

rust-runtime/aws-smithy-http-server/src/request.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use futures_util::{
4343
};
4444
use http::{request::Parts, Extensions, HeaderMap, Request, Uri};
4545

46-
use crate::{rejection::EitherRejection, response::IntoResponse};
46+
use crate::{rejection::any_rejections, response::IntoResponse};
4747

4848
#[doc(hidden)]
4949
#[derive(Debug)]
@@ -139,20 +139,32 @@ where
139139
}
140140
}
141141

142-
impl<P, T1, T2> FromParts<P> for (T1, T2)
143-
where
144-
T1: FromParts<P>,
145-
T2: FromParts<P>,
146-
{
147-
type Rejection = EitherRejection<T1::Rejection, T2::Rejection>;
148-
149-
fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
150-
let t1 = T1::from_parts(parts).map_err(EitherRejection::Left)?;
151-
let t2 = T2::from_parts(parts).map_err(EitherRejection::Right)?;
152-
Ok((t1, t2))
153-
}
142+
macro_rules! impl_from_parts {
143+
($error_name:ident, $($var:ident),+) => (
144+
impl<P, $($var,)*> FromParts<P> for ($($var),*)
145+
where
146+
$($var: FromParts<P>,)*
147+
{
148+
type Rejection = any_rejections::$error_name<$($var::Rejection),*>;
149+
150+
fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
151+
let tuple = (
152+
$($var::from_parts(parts).map_err(any_rejections::$error_name::$var)?,)*
153+
);
154+
Ok(tuple)
155+
}
156+
}
157+
)
154158
}
155159

160+
impl_from_parts!(Two, A, B);
161+
impl_from_parts!(Three, A, B, C);
162+
impl_from_parts!(Four, A, B, C, D);
163+
impl_from_parts!(Five, A, B, C, D, E);
164+
impl_from_parts!(Six, A, B, C, D, E, F);
165+
impl_from_parts!(Seven, A, B, C, D, E, F, G);
166+
impl_from_parts!(Eight, A, B, C, D, E, F, G, H);
167+
156168
/// Provides a protocol aware extraction from a [`Request`]. This consumes the
157169
/// [`Request`], in contrast to [`FromParts`].
158170
pub trait FromRequest<Protocol, B>: Sized {
@@ -180,14 +192,14 @@ where
180192
T1: FromRequest<P, B>,
181193
T2: FromParts<P>,
182194
{
183-
type Rejection = EitherRejection<T1::Rejection, T2::Rejection>;
195+
type Rejection = any_rejections::Two<T1::Rejection, T2::Rejection>;
184196
type Future = TryJoin<MapErr<T1::Future, fn(T1::Rejection) -> Self::Rejection>, Ready<Result<T2, Self::Rejection>>>;
185197

186198
fn from_request(request: Request<B>) -> Self::Future {
187199
let (mut parts, body) = request.into_parts();
188-
let t2_result = T2::from_parts(&mut parts).map_err(EitherRejection::Right);
200+
let t2_result = T2::from_parts(&mut parts).map_err(any_rejections::Two::B);
189201
try_join(
190-
T1::from_request(Request::from_parts(parts, body)).map_err(EitherRejection::Left),
202+
T1::from_request(Request::from_parts(parts, body)).map_err(any_rejections::Two::A),
191203
ready(t2_result),
192204
)
193205
}

0 commit comments

Comments
 (0)