diff --git a/actix-service/CHANGES.md b/actix-service/CHANGES.md index 3b9a9cc0..82c5adb3 100644 --- a/actix-service/CHANGES.md +++ b/actix-service/CHANGES.md @@ -8,9 +8,11 @@ * Migrate pin projections to `pin-project-lite`. [#233] * Remove `AndThenApplyFn` and Pipeline `and_then_apply_fn`. Use the `.and_then(apply_fn(...))` construction. [#233] +* Move non-vital methods to `ServiceExt` and `ServiceFactoryExt` extension traits. [#235] [#232]: https://github.com/actix/actix-net/pull/232 [#233]: https://github.com/actix/actix-net/pull/233 +[#235]: https://github.com/actix/actix-net/pull/235 ## 1.0.6 - 2020-08-09 diff --git a/actix-service/Cargo.toml b/actix-service/Cargo.toml index 60818968..c08bb169 100644 --- a/actix-service/Cargo.toml +++ b/actix-service/Cargo.toml @@ -17,10 +17,9 @@ name = "actix_service" path = "src/lib.rs" [dependencies] -pin-project-lite = "0.2" -futures-util = { version = "0.3.7", default-features = false } futures-core = { version = "0.3.7", default-features = false } +pin-project-lite = "0.2" [dev-dependencies] actix-rt = "1.0.0" -criterion = "0.3" +futures-util = { version = "0.3.7", default-features = false } diff --git a/actix-service/src/and_then.rs b/actix-service/src/and_then.rs index 17d62e8f..fd24cb56 100644 --- a/actix-service/src/and_then.rs +++ b/actix-service/src/and_then.rs @@ -279,9 +279,11 @@ mod tests { task::{Context, Poll}, }; - use futures_util::future::{lazy, ok, ready, Ready}; + use futures_util::future::lazy; - use crate::{fn_factory, pipeline, pipeline_factory, Service, ServiceFactory}; + use crate::{ + fn_factory, ok, pipeline, pipeline_factory, ready, Ready, Service, ServiceFactory, + }; struct Srv1(Rc>); diff --git a/actix-service/src/apply.rs b/actix-service/src/apply.rs index 8db6018f..9b0c4025 100644 --- a/actix-service/src/apply.rs +++ b/actix-service/src/apply.rs @@ -211,10 +211,10 @@ where mod tests { use core::task::Poll; - use futures_util::future::{lazy, ok, Ready}; + use futures_util::future::lazy; use super::*; - use crate::{pipeline, pipeline_factory, Service, ServiceFactory}; + use crate::{ok, pipeline, pipeline_factory, Ready, Service, ServiceFactory}; #[derive(Clone)] struct Srv; diff --git a/actix-service/src/boxed.rs b/actix-service/src/boxed.rs index 203d575c..5c4557df 100644 --- a/actix-service/src/boxed.rs +++ b/actix-service/src/boxed.rs @@ -6,8 +6,6 @@ use core::{ task::{Context, Poll}, }; -use futures_util::future::FutureExt; - use crate::{Service, ServiceFactory}; pub type BoxFuture = Pin>>; @@ -103,11 +101,11 @@ where type Future = BoxFuture>; fn new_service(&self, cfg: Cfg) -> Self::Future { - Box::pin( - self.factory - .new_service(cfg) - .map(|res| res.map(ServiceWrapper::boxed)), - ) + let fut = self.factory.new_service(cfg); + Box::pin(async { + let res = fut.await; + res.map(ServiceWrapper::boxed) + }) } } diff --git a/actix-service/src/ext.rs b/actix-service/src/ext.rs new file mode 100644 index 00000000..e778d11e --- /dev/null +++ b/actix-service/src/ext.rs @@ -0,0 +1,70 @@ +use crate::{dev, Service, ServiceFactory}; + +pub trait ServiceExt: Service { + /// Map this service's output to a different type, returning a new service + /// of the resulting type. + /// + /// This function is similar to the `Option::map` or `Iterator::map` where + /// it will change the type of the underlying service. + /// + /// Note that this function consumes the receiving service and returns a + /// wrapped version of it, similar to the existing `map` methods in the + /// standard library. + fn map(self, f: F) -> dev::Map + where + Self: Sized, + F: FnMut(Self::Response) -> R, + { + dev::Map::new(self, f) + } + + /// Map this service's error to a different error, returning a new service. + /// + /// This function is similar to the `Result::map_err` where it will change + /// the error type of the underlying service. For example, this can be useful to + /// ensure that services have the same error type. + /// + /// Note that this function consumes the receiving service and returns a + /// wrapped version of it. + fn map_err(self, f: F) -> dev::MapErr + where + Self: Sized, + F: Fn(Self::Error) -> E, + { + dev::MapErr::new(self, f) + } +} + +impl ServiceExt for S where S: Service {} + +pub trait ServiceFactoryExt: ServiceFactory { + /// Map this service's output to a different type, returning a new service + /// of the resulting type. + fn map(self, f: F) -> crate::map::MapServiceFactory + where + Self: Sized, + F: FnMut(Self::Response) -> R + Clone, + { + crate::map::MapServiceFactory::new(self, f) + } + + /// Map this service's error to a different error, returning a new service. + fn map_err(self, f: F) -> crate::map_err::MapErrServiceFactory + where + Self: Sized, + F: Fn(Self::Error) -> E + Clone, + { + crate::map_err::MapErrServiceFactory::new(self, f) + } + + /// Map this factory's init error to a different error, returning a new service. + fn map_init_err(self, f: F) -> crate::map_init_err::MapInitErr + where + Self: Sized, + F: Fn(Self::InitError) -> E + Clone, + { + crate::map_init_err::MapInitErr::new(self, f) + } +} + +impl ServiceFactoryExt for S where S: ServiceFactory {} diff --git a/actix-service/src/fn_service.rs b/actix-service/src/fn_service.rs index 59792564..9f7d1eb7 100644 --- a/actix-service/src/fn_service.rs +++ b/actix-service/src/fn_service.rs @@ -1,8 +1,6 @@ use core::{future::Future, marker::PhantomData, task::Poll}; -use futures_util::future::{ok, Ready}; - -use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory}; +use crate::{ok, IntoService, IntoServiceFactory, Ready, Service, ServiceFactory}; /// Create `ServiceFactory` for function that can act as a `Service` pub fn fn_service( @@ -357,10 +355,10 @@ where mod tests { use core::task::Poll; - use futures_util::future::{lazy, ok}; + use futures_util::future::lazy; use super::*; - use crate::{Service, ServiceFactory}; + use crate::{ok, Service, ServiceFactory}; #[actix_rt::test] async fn test_fn_service() { diff --git a/actix-service/src/lib.rs b/actix-service/src/lib.rs index d66d5221..7bf979e5 100644 --- a/actix-service/src/lib.rs +++ b/actix-service/src/lib.rs @@ -19,23 +19,29 @@ mod and_then; mod apply; mod apply_cfg; pub mod boxed; +mod ext; mod fn_service; mod map; mod map_config; mod map_err; mod map_init_err; mod pipeline; +mod ready; mod then; mod transform; mod transform_err; pub use self::apply::{apply_fn, apply_fn_factory}; pub use self::apply_cfg::{apply_cfg, apply_cfg_factory}; +pub use self::ext::{ServiceExt, ServiceFactoryExt}; pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service}; pub use self::map_config::{map_config, unit_config}; pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory}; pub use self::transform::{apply, Transform}; +#[allow(unused_imports)] +use self::ready::{err, ok, ready, Ready}; + /// An asynchronous operation from `Request` to a `Response`. /// /// The `Service` trait models a request/response interaction, receiving requests and returning @@ -110,39 +116,6 @@ pub trait Service { /// Calling `call` without calling `poll_ready` is permitted. The /// implementation must be resilient to this fact. fn call(&mut self, req: Req) -> Self::Future; - - /// Map this service's output to a different type, returning a new service - /// of the resulting type. - /// - /// This function is similar to the `Option::map` or `Iterator::map` where - /// it will change the type of the underlying service. - /// - /// Note that this function consumes the receiving service and returns a - /// wrapped version of it, similar to the existing `map` methods in the - /// standard library. - fn map(self, f: F) -> crate::dev::Map - where - Self: Sized, - F: FnMut(Self::Response) -> R, - { - crate::dev::Map::new(self, f) - } - - /// Map this service's error to a different error, returning a new service. - /// - /// This function is similar to the `Result::map_err` where it will change - /// the error type of the underlying service. For example, this can be useful to - /// ensure that services have the same error type. - /// - /// Note that this function consumes the receiving service and returns a - /// wrapped version of it. - fn map_err(self, f: F) -> crate::dev::MapErr - where - Self: Sized, - F: Fn(Self::Error) -> E, - { - crate::dev::MapErr::new(self, f) - } } /// Factory for creating `Service`s. @@ -175,34 +148,6 @@ pub trait ServiceFactory { /// Create and return a new service asynchronously. fn new_service(&self, cfg: Self::Config) -> Self::Future; - - /// Map this service's output to a different type, returning a new service - /// of the resulting type. - fn map(self, f: F) -> crate::map::MapServiceFactory - where - Self: Sized, - F: FnMut(Self::Response) -> R + Clone, - { - crate::map::MapServiceFactory::new(self, f) - } - - /// Map this service's error to a different error, returning a new service. - fn map_err(self, f: F) -> crate::map_err::MapErrServiceFactory - where - Self: Sized, - F: Fn(Self::Error) -> E + Clone, - { - crate::map_err::MapErrServiceFactory::new(self, f) - } - - /// Map this factory's init error to a different error, returning a new service. - fn map_init_err(self, f: F) -> crate::map_init_err::MapInitErr - where - Self: Sized, - F: Fn(Self::InitError) -> E + Clone, - { - crate::map_init_err::MapInitErr::new(self, f) - } } impl<'a, S, Req> Service for &'a mut S diff --git a/actix-service/src/map.rs b/actix-service/src/map.rs index a8afa25f..0599a1d8 100644 --- a/actix-service/src/map.rs +++ b/actix-service/src/map.rs @@ -199,10 +199,12 @@ where #[cfg(test)] mod tests { - use futures_util::future::{lazy, ok, Ready}; + use futures_util::future::lazy; use super::*; - use crate::{IntoServiceFactory, Service, ServiceFactory}; + use crate::{ + ok, IntoServiceFactory, Ready, Service, ServiceExt, ServiceFactory, ServiceFactoryExt, + }; struct Srv; diff --git a/actix-service/src/map_err.rs b/actix-service/src/map_err.rs index f0bf134b..944056c2 100644 --- a/actix-service/src/map_err.rs +++ b/actix-service/src/map_err.rs @@ -203,10 +203,13 @@ where #[cfg(test)] mod tests { - use futures_util::future::{err, lazy, ok, Ready}; + use futures_util::future::lazy; use super::*; - use crate::{IntoServiceFactory, Service, ServiceFactory}; + use crate::{ + err, ok, IntoServiceFactory, Ready, Service, ServiceExt, ServiceFactory, + ServiceFactoryExt, + }; struct Srv; diff --git a/actix-service/src/ready.rs b/actix-service/src/ready.rs new file mode 100644 index 00000000..8b0c2ea7 --- /dev/null +++ b/actix-service/src/ready.rs @@ -0,0 +1,54 @@ +//! When MSRV is 1.48, replace with `core::future::Ready` and `core::future::ready()`. + +use core::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; + +/// Future for the [`ready`](ready()) function. +#[derive(Debug, Clone)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Ready { + val: Option, +} + +impl Ready { + /// Unwraps the value from this immediately ready future. + #[inline] + pub fn into_inner(mut self) -> T { + self.val.take().unwrap() + } +} + +impl Unpin for Ready {} + +impl Future for Ready { + type Output = T; + + #[inline] + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + let val = self.val.take().expect("Ready can not be polled twice."); + Poll::Ready(val) + } +} + +/// Creates a future that is immediately ready with a value. +#[allow(dead_code)] +pub(crate) fn ready(val: T) -> Ready { + Ready { val: Some(val) } +} + +/// Create a future that is immediately ready with a success value. +#[allow(dead_code)] +pub(crate) fn ok(val: T) -> Ready> { + Ready { val: Some(Ok(val)) } +} + +/// Create a future that is immediately ready with an error value. +#[allow(dead_code)] +pub(crate) fn err(err: E) -> Ready> { + Ready { + val: Some(Err(err)), + } +} diff --git a/actix-service/src/then.rs b/actix-service/src/then.rs index 179713ac..060ca9c7 100644 --- a/actix-service/src/then.rs +++ b/actix-service/src/then.rs @@ -254,9 +254,9 @@ mod tests { task::{Context, Poll}, }; - use futures_util::future::{err, lazy, ok, ready, Ready}; + use futures_util::future::lazy; - use crate::{pipeline, pipeline_factory, Service, ServiceFactory}; + use crate::{err, ok, pipeline, pipeline_factory, ready, Ready, Service, ServiceFactory}; #[derive(Clone)] struct Srv1(Rc>);