Loading CHANGELOG.next.toml +10 −0 Original line number Diff line number Diff line Loading @@ -105,3 +105,13 @@ author = "david-perez" references = ["smithy-rs#2676", "smithy-rs#2685"] meta = { "breaking" = true, "tada" = false, "bug" = false } [[smithy-rs]] message = """Remove `PollError` from an operations `Service::Error`. Any [`tower::Service`](https://docs.rs/tower/latest/tower/trait.Service.html) provided to [`Operation::from_service`](https://docs.rs/aws-smithy-http-server/latest/aws_smithy_http_server/operation/struct.Operation.html#method.from_service) no longer requires `Service::Error = OperationError<Op::Error, PollError>`, instead requiring just `Service::Error = Op::Error`. """ references = ["smithy-rs#2457"] meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "server" } author = "hlbarber" rust-runtime/aws-smithy-http-server/src/operation/handler.rs +5 −8 Original line number Diff line number Diff line Loading @@ -10,13 +10,10 @@ use std::{ task::{Context, Poll}, }; use futures_util::{ future::{Map, MapErr}, FutureExt, TryFutureExt, }; use futures_util::{future::Map, FutureExt}; use tower::Service; use super::{OperationError, OperationShape}; use super::OperationShape; /// A utility trait used to provide an even interface for all operation handlers. /// Loading Loading @@ -143,14 +140,14 @@ where H: Handler<Op, Exts>, { type Response = Op::Output; type Error = OperationError<Op::Error, Infallible>; type Future = MapErr<H::Future, fn(Op::Error) -> Self::Error>; type Error = Op::Error; type Future = H::Future; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } fn call(&mut self, (input, exts): (Op::Input, Exts)) -> Self::Future { self.handler.call(input, exts).map_err(OperationError::Model) self.handler.call(input, exts) } } rust-runtime/aws-smithy-http-server/src/operation/mod.rs +12 −32 Original line number Diff line number Diff line Loading @@ -84,16 +84,13 @@ //! ## [`OperationService`] //! //! Similarly, the [`OperationService`] trait is implemented by all `Service<(Op::Input, ...)>` with //! `Response = Op::Output`, and `Error = OperationError<Op::Error, PollError>`. //! //! We use [`OperationError`], with a `PollError` not constrained by the model, to allow the user to provide a custom //! [`Service::poll_ready`](tower::Service::poll_ready) implementation. //! `Response = Op::Output`, and `Error = Op::Error`. //! //! The following are examples of [`Service`](tower::Service)s which implement [`OperationService`]: //! //! - `Service<CartIdentifier, Response = ShoppingCart, Error = OperationError<Infallible, Infallible>>`. //! - `Service<(CartIdentifier, Extension<Context>), Response = ShoppingCart, Error = OperationError<GetShoppingCartError, Infallible>>`. //! - `Service<(CartIdentifier, Extension<Context>, Extension<ExtraContext>), Response = ShoppingCart, Error = OperationError<GetShoppingCartError, PollError>)`. //! - `Service<CartIdentifier, Response = ShoppingCart, Error = Infallible>`. //! - `Service<(CartIdentifier, Extension<Context>), Response = ShoppingCart, Error = GetShoppingCartError>`. //! - `Service<(CartIdentifier, Extension<Context>, Extension<ExtraContext>), Response = ShoppingCart, Error = GetShoppingCartError)`. //! //! Notice the parallels between [`OperationService`] and [`Handler`]. //! Loading @@ -116,7 +113,7 @@ //! # type Output = ShoppingCart; //! # type Error = GetShoppingError; //! # } //! # type OpFuture = std::future::Ready<Result<ShoppingCart, OperationError<GetShoppingError, PollError>>>; //! # type OpFuture = std::future::Ready<Result<ShoppingCart, GetShoppingError>>; //! // Construction of an `Operation` from a `Handler`. //! //! async fn op_handler(input: CartIdentifier) -> Result<ShoppingCart, GetShoppingError> { Loading @@ -127,13 +124,11 @@ //! //! // Construction of an `Operation` from a `Service`. //! //! pub struct PollError; //! //! pub struct OpService; //! //! impl Service<CartIdentifier> for OpService { //! type Response = ShoppingCart; //! type Error = OperationError<GetShoppingError, PollError>; //! type Error = GetShoppingError; //! type Future = OpFuture; //! //! fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> { Loading @@ -155,19 +150,13 @@ //! //! Both [`Handler`] and [`OperationService`] accept and return Smithy model structures. After an [`Operation`] is //! constructed they are converted to a canonical form //! `Service<(Op::Input, Exts), Response = Op::Output, Error = OperationError<Op::Error, PollError>>`. The //! `Service<(Op::Input, Exts), Response = Op::Output, Error = Op::Error>`. The //! [`UpgradeLayer`] acts upon such services by converting them to //! `Service<http::Request, Response = http::Response, Error = PollError>`. //! `Service<http::Request, Response = http::Response, Error = Infallible>`. //! //! Note that the `PollError` is still exposed, for two reasons: //! //! - Smithy is agnostic to `PollError` and therefore we have no prescribed way to serialize it to a [`http::Response`] //! , unlike the operation errors. //! - The intention of `PollError` is to signal that the underlying service is no longer able to take requests, so //! should be discarded. See [`Service::poll_ready`](tower::Service::poll_ready). //! //! The [`UpgradeLayer`] and it's [`Layer::Service`](tower::Layer::Service) [`Upgrade`] are both parameterized by a //! protocol. This allows for upgrading to `Service<http::Request, Response = http::Response, Error = PollError>` to be //! protocol. This allows for upgrading to `Service<http::Request, Response = http::Response, Error = Infallible>` to be //! protocol dependent. //! //! The [`Operation::upgrade`] will apply [`UpgradeLayer`] to `S` then apply the [`Layer`](tower::Layer) `L`. The Loading Loading @@ -208,15 +197,15 @@ impl<S, L> Operation<S, L> { } } impl<Op, S, PollError> Operation<Normalize<Op, S, PollError>> { impl<Op, S> Operation<Normalize<Op, S>> { /// Creates an [`Operation`] from a [`Service`](tower::Service). pub fn from_service<Exts>(inner: S) -> Self where Op: OperationShape, S: OperationService<Op, Exts, PollError>, S: OperationService<Op, Exts>, { Self { inner: inner.canonicalize(), inner: inner.normalize(), layer: Identity::new(), } } Loading @@ -235,12 +224,3 @@ impl<Op, H> Operation<IntoService<Op, H>> { } } } /// The operation [`Service`](tower::Service) has two classes of failure modes - those specified by the Smithy model /// and those associated with [`Service::poll_ready`](tower::Service::poll_ready). pub enum OperationError<ModelError, PollError> { /// An error modelled by the Smithy model occurred. Model(ModelError), /// A [`Service::poll_ready`](tower::Service::poll_ready) failure occurred. PollReady(PollError), } rust-runtime/aws-smithy-http-server/src/operation/operation_service.rs +16 −20 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ use std::{ use tower::Service; use super::{OperationError, OperationShape}; use super::OperationShape; /// A utility trait used to provide an even interface for all operation services. /// Loading @@ -19,8 +19,7 @@ use super::{OperationError, OperationShape}; /// [`IntoService`](super::IntoService). /// /// See [`operation`](crate::operation) documentation for more info. pub trait OperationService<Op, Exts, PollError>: Service<Self::Normalized, Response = Op::Output, Error = OperationError<Op::Error, PollError>> pub trait OperationService<Op, Exts>: Service<Self::Normalized, Response = Op::Output, Error = Op::Error> where Op: OperationShape, { Loading @@ -31,10 +30,10 @@ where } // `Service<Op::Input>` impl<Op, S, PollError> OperationService<Op, (), PollError> for S impl<Op, S> OperationService<Op, ()> for S where Op: OperationShape, S: Service<Op::Input, Response = Op::Output, Error = OperationError<Op::Error, PollError>>, S: Service<Op::Input, Response = Op::Output, Error = Op::Error>, { type Normalized = Op::Input; Loading @@ -44,10 +43,10 @@ where } // `Service<(Op::Input, Ext0)>` impl<Op, Ext0, S, PollError> OperationService<Op, (Ext0,), PollError> for S impl<Op, Ext0, S> OperationService<Op, (Ext0,)> for S where Op: OperationShape, S: Service<(Op::Input, Ext0), Response = Op::Output, Error = OperationError<Op::Error, PollError>>, S: Service<(Op::Input, Ext0), Response = Op::Output, Error = Op::Error>, { type Normalized = (Op::Input, Ext0); Loading @@ -57,10 +56,10 @@ where } // `Service<(Op::Input, Ext0, Ext1)>` impl<Op, Ext0, Ext1, S, PollError> OperationService<Op, (Ext0, Ext1), PollError> for S impl<Op, Ext0, Ext1, S> OperationService<Op, (Ext0, Ext1)> for S where Op: OperationShape, S: Service<(Op::Input, Ext0, Ext1), Response = Op::Output, Error = OperationError<Op::Error, PollError>>, S: Service<(Op::Input, Ext0, Ext1), Response = Op::Output, Error = Op::Error>, { type Normalized = (Op::Input, Ext0, Ext1); Loading @@ -70,39 +69,37 @@ where } /// An extension trait of [`OperationService`]. pub trait OperationServiceExt<Op, Exts, PollError>: OperationService<Op, Exts, PollError> pub trait OperationServiceExt<Op, Exts>: OperationService<Op, Exts> where Op: OperationShape, { /// Convert the [`OperationService`] into a canonicalized [`Service`]. fn canonicalize(self) -> Normalize<Op, Self, PollError> fn normalize(self) -> Normalize<Op, Self> where Self: Sized, { Normalize { inner: self, _operation: PhantomData, _poll_error: PhantomData, } } } impl<F, Op, Exts, PollError> OperationServiceExt<Op, Exts, PollError> for F impl<F, Op, Exts> OperationServiceExt<Op, Exts> for F where Op: OperationShape, F: OperationService<Op, Exts, PollError>, F: OperationService<Op, Exts>, { } /// A [`Service`] normalizing the request type of a [`OperationService`]. #[derive(Debug)] pub struct Normalize<Op, S, PollError> { pub struct Normalize<Op, S> { inner: S, _operation: PhantomData<Op>, _poll_error: PhantomData<PollError>, } impl<Op, S, PollError> Clone for Normalize<Op, S, PollError> impl<Op, S> Clone for Normalize<Op, S> where S: Clone, { Loading @@ -110,15 +107,14 @@ where Self { inner: self.inner.clone(), _operation: PhantomData, _poll_error: PhantomData, } } } impl<Op, S, Exts, PollError> Service<(Op::Input, Exts)> for Normalize<Op, S, PollError> impl<Op, S, Exts> Service<(Op::Input, Exts)> for Normalize<Op, S> where Op: OperationShape, S: OperationService<Op, Exts, PollError>, S: OperationService<Op, Exts>, { type Response = S::Response; type Error = S::Error; Loading rust-runtime/aws-smithy-http-server/src/operation/shape.rs +2 −2 Original line number Diff line number Diff line Loading @@ -33,9 +33,9 @@ pub trait OperationShapeExt: OperationShape { } /// Creates a new [`Operation`] for well-formed [`Service`](tower::Service)s. fn from_service<S, Exts, PollError>(svc: S) -> Operation<Normalize<Self, S, PollError>> fn from_service<S, Exts>(svc: S) -> Operation<Normalize<Self, S>> where S: OperationService<Self, Exts, PollError>, S: OperationService<Self, Exts>, Self: Sized, { Operation::from_service(svc) Loading Loading
CHANGELOG.next.toml +10 −0 Original line number Diff line number Diff line Loading @@ -105,3 +105,13 @@ author = "david-perez" references = ["smithy-rs#2676", "smithy-rs#2685"] meta = { "breaking" = true, "tada" = false, "bug" = false } [[smithy-rs]] message = """Remove `PollError` from an operations `Service::Error`. Any [`tower::Service`](https://docs.rs/tower/latest/tower/trait.Service.html) provided to [`Operation::from_service`](https://docs.rs/aws-smithy-http-server/latest/aws_smithy_http_server/operation/struct.Operation.html#method.from_service) no longer requires `Service::Error = OperationError<Op::Error, PollError>`, instead requiring just `Service::Error = Op::Error`. """ references = ["smithy-rs#2457"] meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "server" } author = "hlbarber"
rust-runtime/aws-smithy-http-server/src/operation/handler.rs +5 −8 Original line number Diff line number Diff line Loading @@ -10,13 +10,10 @@ use std::{ task::{Context, Poll}, }; use futures_util::{ future::{Map, MapErr}, FutureExt, TryFutureExt, }; use futures_util::{future::Map, FutureExt}; use tower::Service; use super::{OperationError, OperationShape}; use super::OperationShape; /// A utility trait used to provide an even interface for all operation handlers. /// Loading Loading @@ -143,14 +140,14 @@ where H: Handler<Op, Exts>, { type Response = Op::Output; type Error = OperationError<Op::Error, Infallible>; type Future = MapErr<H::Future, fn(Op::Error) -> Self::Error>; type Error = Op::Error; type Future = H::Future; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } fn call(&mut self, (input, exts): (Op::Input, Exts)) -> Self::Future { self.handler.call(input, exts).map_err(OperationError::Model) self.handler.call(input, exts) } }
rust-runtime/aws-smithy-http-server/src/operation/mod.rs +12 −32 Original line number Diff line number Diff line Loading @@ -84,16 +84,13 @@ //! ## [`OperationService`] //! //! Similarly, the [`OperationService`] trait is implemented by all `Service<(Op::Input, ...)>` with //! `Response = Op::Output`, and `Error = OperationError<Op::Error, PollError>`. //! //! We use [`OperationError`], with a `PollError` not constrained by the model, to allow the user to provide a custom //! [`Service::poll_ready`](tower::Service::poll_ready) implementation. //! `Response = Op::Output`, and `Error = Op::Error`. //! //! The following are examples of [`Service`](tower::Service)s which implement [`OperationService`]: //! //! - `Service<CartIdentifier, Response = ShoppingCart, Error = OperationError<Infallible, Infallible>>`. //! - `Service<(CartIdentifier, Extension<Context>), Response = ShoppingCart, Error = OperationError<GetShoppingCartError, Infallible>>`. //! - `Service<(CartIdentifier, Extension<Context>, Extension<ExtraContext>), Response = ShoppingCart, Error = OperationError<GetShoppingCartError, PollError>)`. //! - `Service<CartIdentifier, Response = ShoppingCart, Error = Infallible>`. //! - `Service<(CartIdentifier, Extension<Context>), Response = ShoppingCart, Error = GetShoppingCartError>`. //! - `Service<(CartIdentifier, Extension<Context>, Extension<ExtraContext>), Response = ShoppingCart, Error = GetShoppingCartError)`. //! //! Notice the parallels between [`OperationService`] and [`Handler`]. //! Loading @@ -116,7 +113,7 @@ //! # type Output = ShoppingCart; //! # type Error = GetShoppingError; //! # } //! # type OpFuture = std::future::Ready<Result<ShoppingCart, OperationError<GetShoppingError, PollError>>>; //! # type OpFuture = std::future::Ready<Result<ShoppingCart, GetShoppingError>>; //! // Construction of an `Operation` from a `Handler`. //! //! async fn op_handler(input: CartIdentifier) -> Result<ShoppingCart, GetShoppingError> { Loading @@ -127,13 +124,11 @@ //! //! // Construction of an `Operation` from a `Service`. //! //! pub struct PollError; //! //! pub struct OpService; //! //! impl Service<CartIdentifier> for OpService { //! type Response = ShoppingCart; //! type Error = OperationError<GetShoppingError, PollError>; //! type Error = GetShoppingError; //! type Future = OpFuture; //! //! fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> { Loading @@ -155,19 +150,13 @@ //! //! Both [`Handler`] and [`OperationService`] accept and return Smithy model structures. After an [`Operation`] is //! constructed they are converted to a canonical form //! `Service<(Op::Input, Exts), Response = Op::Output, Error = OperationError<Op::Error, PollError>>`. The //! `Service<(Op::Input, Exts), Response = Op::Output, Error = Op::Error>`. The //! [`UpgradeLayer`] acts upon such services by converting them to //! `Service<http::Request, Response = http::Response, Error = PollError>`. //! `Service<http::Request, Response = http::Response, Error = Infallible>`. //! //! Note that the `PollError` is still exposed, for two reasons: //! //! - Smithy is agnostic to `PollError` and therefore we have no prescribed way to serialize it to a [`http::Response`] //! , unlike the operation errors. //! - The intention of `PollError` is to signal that the underlying service is no longer able to take requests, so //! should be discarded. See [`Service::poll_ready`](tower::Service::poll_ready). //! //! The [`UpgradeLayer`] and it's [`Layer::Service`](tower::Layer::Service) [`Upgrade`] are both parameterized by a //! protocol. This allows for upgrading to `Service<http::Request, Response = http::Response, Error = PollError>` to be //! protocol. This allows for upgrading to `Service<http::Request, Response = http::Response, Error = Infallible>` to be //! protocol dependent. //! //! The [`Operation::upgrade`] will apply [`UpgradeLayer`] to `S` then apply the [`Layer`](tower::Layer) `L`. The Loading Loading @@ -208,15 +197,15 @@ impl<S, L> Operation<S, L> { } } impl<Op, S, PollError> Operation<Normalize<Op, S, PollError>> { impl<Op, S> Operation<Normalize<Op, S>> { /// Creates an [`Operation`] from a [`Service`](tower::Service). pub fn from_service<Exts>(inner: S) -> Self where Op: OperationShape, S: OperationService<Op, Exts, PollError>, S: OperationService<Op, Exts>, { Self { inner: inner.canonicalize(), inner: inner.normalize(), layer: Identity::new(), } } Loading @@ -235,12 +224,3 @@ impl<Op, H> Operation<IntoService<Op, H>> { } } } /// The operation [`Service`](tower::Service) has two classes of failure modes - those specified by the Smithy model /// and those associated with [`Service::poll_ready`](tower::Service::poll_ready). pub enum OperationError<ModelError, PollError> { /// An error modelled by the Smithy model occurred. Model(ModelError), /// A [`Service::poll_ready`](tower::Service::poll_ready) failure occurred. PollReady(PollError), }
rust-runtime/aws-smithy-http-server/src/operation/operation_service.rs +16 −20 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ use std::{ use tower::Service; use super::{OperationError, OperationShape}; use super::OperationShape; /// A utility trait used to provide an even interface for all operation services. /// Loading @@ -19,8 +19,7 @@ use super::{OperationError, OperationShape}; /// [`IntoService`](super::IntoService). /// /// See [`operation`](crate::operation) documentation for more info. pub trait OperationService<Op, Exts, PollError>: Service<Self::Normalized, Response = Op::Output, Error = OperationError<Op::Error, PollError>> pub trait OperationService<Op, Exts>: Service<Self::Normalized, Response = Op::Output, Error = Op::Error> where Op: OperationShape, { Loading @@ -31,10 +30,10 @@ where } // `Service<Op::Input>` impl<Op, S, PollError> OperationService<Op, (), PollError> for S impl<Op, S> OperationService<Op, ()> for S where Op: OperationShape, S: Service<Op::Input, Response = Op::Output, Error = OperationError<Op::Error, PollError>>, S: Service<Op::Input, Response = Op::Output, Error = Op::Error>, { type Normalized = Op::Input; Loading @@ -44,10 +43,10 @@ where } // `Service<(Op::Input, Ext0)>` impl<Op, Ext0, S, PollError> OperationService<Op, (Ext0,), PollError> for S impl<Op, Ext0, S> OperationService<Op, (Ext0,)> for S where Op: OperationShape, S: Service<(Op::Input, Ext0), Response = Op::Output, Error = OperationError<Op::Error, PollError>>, S: Service<(Op::Input, Ext0), Response = Op::Output, Error = Op::Error>, { type Normalized = (Op::Input, Ext0); Loading @@ -57,10 +56,10 @@ where } // `Service<(Op::Input, Ext0, Ext1)>` impl<Op, Ext0, Ext1, S, PollError> OperationService<Op, (Ext0, Ext1), PollError> for S impl<Op, Ext0, Ext1, S> OperationService<Op, (Ext0, Ext1)> for S where Op: OperationShape, S: Service<(Op::Input, Ext0, Ext1), Response = Op::Output, Error = OperationError<Op::Error, PollError>>, S: Service<(Op::Input, Ext0, Ext1), Response = Op::Output, Error = Op::Error>, { type Normalized = (Op::Input, Ext0, Ext1); Loading @@ -70,39 +69,37 @@ where } /// An extension trait of [`OperationService`]. pub trait OperationServiceExt<Op, Exts, PollError>: OperationService<Op, Exts, PollError> pub trait OperationServiceExt<Op, Exts>: OperationService<Op, Exts> where Op: OperationShape, { /// Convert the [`OperationService`] into a canonicalized [`Service`]. fn canonicalize(self) -> Normalize<Op, Self, PollError> fn normalize(self) -> Normalize<Op, Self> where Self: Sized, { Normalize { inner: self, _operation: PhantomData, _poll_error: PhantomData, } } } impl<F, Op, Exts, PollError> OperationServiceExt<Op, Exts, PollError> for F impl<F, Op, Exts> OperationServiceExt<Op, Exts> for F where Op: OperationShape, F: OperationService<Op, Exts, PollError>, F: OperationService<Op, Exts>, { } /// A [`Service`] normalizing the request type of a [`OperationService`]. #[derive(Debug)] pub struct Normalize<Op, S, PollError> { pub struct Normalize<Op, S> { inner: S, _operation: PhantomData<Op>, _poll_error: PhantomData<PollError>, } impl<Op, S, PollError> Clone for Normalize<Op, S, PollError> impl<Op, S> Clone for Normalize<Op, S> where S: Clone, { Loading @@ -110,15 +107,14 @@ where Self { inner: self.inner.clone(), _operation: PhantomData, _poll_error: PhantomData, } } } impl<Op, S, Exts, PollError> Service<(Op::Input, Exts)> for Normalize<Op, S, PollError> impl<Op, S, Exts> Service<(Op::Input, Exts)> for Normalize<Op, S> where Op: OperationShape, S: OperationService<Op, Exts, PollError>, S: OperationService<Op, Exts>, { type Response = S::Response; type Error = S::Error; Loading
rust-runtime/aws-smithy-http-server/src/operation/shape.rs +2 −2 Original line number Diff line number Diff line Loading @@ -33,9 +33,9 @@ pub trait OperationShapeExt: OperationShape { } /// Creates a new [`Operation`] for well-formed [`Service`](tower::Service)s. fn from_service<S, Exts, PollError>(svc: S) -> Operation<Normalize<Self, S, PollError>> fn from_service<S, Exts>(svc: S) -> Operation<Normalize<Self, S>> where S: OperationService<Self, Exts, PollError>, S: OperationService<Self, Exts>, Self: Sized, { Operation::from_service(svc) Loading