mirror of
https://github.com/actix/actix-web.git
synced 2024-12-22 16:16:40 +00:00
add some doc apis and tests
This commit is contained in:
parent
f66eec00e7
commit
62dbe1b001
6 changed files with 299 additions and 29 deletions
|
@ -5,7 +5,10 @@ use futures::{Async, Future, Poll};
|
||||||
|
|
||||||
use super::{IntoNewService, NewService, Service};
|
use super::{IntoNewService, NewService, Service};
|
||||||
|
|
||||||
/// `AndThen` service combinator
|
/// Service for the `and_then` combinator, chaining a computation onto the end
|
||||||
|
/// of another service which completes successfully.
|
||||||
|
///
|
||||||
|
/// This is created by the `ServiceExt::and_then` method.
|
||||||
pub struct AndThen<A, B> {
|
pub struct AndThen<A, B> {
|
||||||
a: A,
|
a: A,
|
||||||
b: Rc<RefCell<B>>,
|
b: Rc<RefCell<B>>,
|
||||||
|
@ -218,3 +221,69 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use futures::future::{ok, FutureResult};
|
||||||
|
use futures::{Async, Poll};
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use service::{Service, ServiceExt};
|
||||||
|
|
||||||
|
struct Srv1(Rc<Cell<usize>>);
|
||||||
|
impl Service for Srv1 {
|
||||||
|
type Request = &'static str;
|
||||||
|
type Response = &'static str;
|
||||||
|
type Error = ();
|
||||||
|
type Future = FutureResult<Self::Response, ()>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
self.0.set(self.0.get() + 1);
|
||||||
|
Ok(Async::Ready(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||||
|
ok(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Srv2(Rc<Cell<usize>>);
|
||||||
|
|
||||||
|
impl Service for Srv2 {
|
||||||
|
type Request = &'static str;
|
||||||
|
type Response = (&'static str, &'static str);
|
||||||
|
type Error = ();
|
||||||
|
type Future = FutureResult<Self::Response, ()>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
self.0.set(self.0.get() + 1);
|
||||||
|
Ok(Async::Ready(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||||
|
ok((req, "srv2"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poll_ready() {
|
||||||
|
let cnt = Rc::new(Cell::new(0));
|
||||||
|
let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt.clone()));
|
||||||
|
let res = srv.poll_ready();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), Async::Ready(()));
|
||||||
|
assert_eq!(cnt.get(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_call() {
|
||||||
|
let cnt = Rc::new(Cell::new(0));
|
||||||
|
let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt));
|
||||||
|
let res = srv.call("srv1").poll();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), Async::Ready(("srv1", "srv2")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -167,3 +167,37 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use futures::future::{ok, FutureResult};
|
||||||
|
use futures::{Async, Future, Poll};
|
||||||
|
|
||||||
|
use service::{Service, ServiceExt};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Srv;
|
||||||
|
impl Service for Srv {
|
||||||
|
type Request = ();
|
||||||
|
type Response = ();
|
||||||
|
type Error = ();
|
||||||
|
type Future = FutureResult<(), ()>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
Ok(Async::Ready(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, _: ()) -> Self::Future {
|
||||||
|
ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_call() {
|
||||||
|
let mut srv =
|
||||||
|
Srv.apply(|req: &'static str, srv| srv.call(()).map(move |res| (req, res)));
|
||||||
|
let res = srv.call("srv").poll();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), Async::Ready(("srv", ())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ use futures::{Future, Poll};
|
||||||
|
|
||||||
use super::Service;
|
use super::Service;
|
||||||
|
|
||||||
|
/// Service for the `from_err` combinator, changing the error type of a service.
|
||||||
|
///
|
||||||
|
/// This is created by the `ServiceExt::from_err` method.
|
||||||
pub struct FromErr<A, E>
|
pub struct FromErr<A, E>
|
||||||
where
|
where
|
||||||
A: Service,
|
A: Service,
|
||||||
|
@ -73,3 +76,52 @@ where
|
||||||
self.fut.poll().map_err(E::from)
|
self.fut.poll().map_err(E::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use futures::future::{err, FutureResult};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use service::{Service, ServiceExt};
|
||||||
|
|
||||||
|
struct Srv;
|
||||||
|
impl Service for Srv {
|
||||||
|
type Request = ();
|
||||||
|
type Response = ();
|
||||||
|
type Error = ();
|
||||||
|
type Future = FutureResult<(), ()>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, _: ()) -> Self::Future {
|
||||||
|
err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct Error;
|
||||||
|
|
||||||
|
impl From<()> for Error {
|
||||||
|
fn from(_: ()) -> Self {
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poll_ready() {
|
||||||
|
let mut srv = Srv.from_err::<Error>();
|
||||||
|
let res = srv.poll_ready();
|
||||||
|
assert!(res.is_err());
|
||||||
|
assert_eq!(res.err().unwrap(), Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_call() {
|
||||||
|
let mut srv = Srv.from_err::<Error>();
|
||||||
|
let res = srv.call(()).poll();
|
||||||
|
assert!(res.is_err());
|
||||||
|
assert_eq!(res.err().unwrap(), Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,16 @@ use futures::{Async, Future, Poll};
|
||||||
|
|
||||||
use super::{NewService, Service};
|
use super::{NewService, Service};
|
||||||
|
|
||||||
/// `Map` service combinator
|
/// Service for the `map` combinator, changing the type of a service's response.
|
||||||
pub struct Map<A, F, R> {
|
///
|
||||||
a: A,
|
/// This is created by the `ServiceExt::map` method.
|
||||||
|
pub struct Map<A, F, R>
|
||||||
|
where
|
||||||
|
A: Service,
|
||||||
|
F: Fn(A::Response) -> R,
|
||||||
|
{
|
||||||
|
service: A,
|
||||||
f: F,
|
f: F,
|
||||||
r: marker::PhantomData<R>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, F, R> Map<A, F, R>
|
impl<A, F, R> Map<A, F, R>
|
||||||
|
@ -17,12 +22,8 @@ where
|
||||||
F: Fn(A::Response) -> R,
|
F: Fn(A::Response) -> R,
|
||||||
{
|
{
|
||||||
/// Create new `Map` combinator
|
/// Create new `Map` combinator
|
||||||
pub fn new(a: A, f: F) -> Self {
|
pub fn new(service: A, f: F) -> Self {
|
||||||
Self {
|
Self { service, f }
|
||||||
a,
|
|
||||||
f,
|
|
||||||
r: marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +34,8 @@ where
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Map {
|
Map {
|
||||||
a: self.a.clone(),
|
service: self.service.clone(),
|
||||||
f: self.f.clone(),
|
f: self.f.clone(),
|
||||||
r: marker::PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,11 +51,11 @@ where
|
||||||
type Future = MapFuture<A, F, R>;
|
type Future = MapFuture<A, F, R>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
self.a.poll_ready()
|
self.service.poll_ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Self::Request) -> Self::Future {
|
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||||
MapFuture::new(self.a.call(req), self.f.clone())
|
MapFuture::new(self.service.call(req), self.f.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,3 +183,43 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use futures::future::{ok, FutureResult};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use service::{Service, ServiceExt};
|
||||||
|
|
||||||
|
struct Srv;
|
||||||
|
impl Service for Srv {
|
||||||
|
type Request = ();
|
||||||
|
type Response = ();
|
||||||
|
type Error = ();
|
||||||
|
type Future = FutureResult<(), ()>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
Ok(Async::Ready(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, _: ()) -> Self::Future {
|
||||||
|
ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poll_ready() {
|
||||||
|
let mut srv = Srv.map(|_| "ok");
|
||||||
|
let res = srv.poll_ready();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), Async::Ready(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_call() {
|
||||||
|
let mut srv = Srv.map(|_| "ok");
|
||||||
|
let res = srv.call(()).poll();
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), Async::Ready("ok"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,17 @@ use futures::{Async, Future, Poll};
|
||||||
|
|
||||||
use super::{NewService, Service};
|
use super::{NewService, Service};
|
||||||
|
|
||||||
/// `MapErr` service combinator
|
/// Service for the `map_err` combinator, changing the type of a service's
|
||||||
pub struct MapErr<A, F, E> {
|
/// error.
|
||||||
a: A,
|
///
|
||||||
|
/// This is created by the `ServiceExt::map_err` method.
|
||||||
|
pub struct MapErr<A, F, E>
|
||||||
|
where
|
||||||
|
A: Service,
|
||||||
|
F: Fn(A::Error) -> E,
|
||||||
|
{
|
||||||
|
service: A,
|
||||||
f: F,
|
f: F,
|
||||||
e: marker::PhantomData<E>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, F, E> MapErr<A, F, E>
|
impl<A, F, E> MapErr<A, F, E>
|
||||||
|
@ -17,12 +23,8 @@ where
|
||||||
F: Fn(A::Error) -> E,
|
F: Fn(A::Error) -> E,
|
||||||
{
|
{
|
||||||
/// Create new `MapErr` combinator
|
/// Create new `MapErr` combinator
|
||||||
pub fn new(a: A, f: F) -> Self {
|
pub fn new(service: A, f: F) -> Self {
|
||||||
Self {
|
Self { service, f }
|
||||||
a,
|
|
||||||
f,
|
|
||||||
e: marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +35,8 @@ where
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
MapErr {
|
MapErr {
|
||||||
a: self.a.clone(),
|
service: self.service.clone(),
|
||||||
f: self.f.clone(),
|
f: self.f.clone(),
|
||||||
e: marker::PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,11 +53,11 @@ where
|
||||||
type Future = MapErrFuture<A, F, E>;
|
type Future = MapErrFuture<A, F, E>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
self.a.poll_ready().map_err(&self.f)
|
self.service.poll_ready().map_err(&self.f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Self::Request) -> Self::Future {
|
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||||
MapErrFuture::new(self.a.call(req), self.f.clone())
|
MapErrFuture::new(self.service.call(req), self.f.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,3 +182,44 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use futures::future::{err, FutureResult};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use service::{Service, ServiceExt};
|
||||||
|
|
||||||
|
struct Srv;
|
||||||
|
|
||||||
|
impl Service for Srv {
|
||||||
|
type Request = ();
|
||||||
|
type Response = ();
|
||||||
|
type Error = ();
|
||||||
|
type Future = FutureResult<(), ()>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, _: ()) -> Self::Future {
|
||||||
|
err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_poll_ready() {
|
||||||
|
let mut srv = Srv.map_err(|_| "error");
|
||||||
|
let res = srv.poll_ready();
|
||||||
|
assert!(res.is_err());
|
||||||
|
assert_eq!(res.err().unwrap(), "error");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_call() {
|
||||||
|
let mut srv = Srv.map_err(|_| "error");
|
||||||
|
let res = srv.call(()).poll();
|
||||||
|
assert!(res.is_err());
|
||||||
|
assert_eq!(res.err().unwrap(), "error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ pub use self::map::{Map, MapNewService};
|
||||||
pub use self::map_err::{MapErr, MapErrNewService};
|
pub use self::map_err::{MapErr, MapErrNewService};
|
||||||
pub use self::map_init_err::MapInitErr;
|
pub use self::map_init_err::MapInitErr;
|
||||||
|
|
||||||
|
/// An extension trait for `Service`s that provides a variety of convenient
|
||||||
|
/// adapters
|
||||||
pub trait ServiceExt: Service {
|
pub trait ServiceExt: Service {
|
||||||
fn apply<F, R, Req>(self, f: F) -> Apply<Self, F, R, Req>
|
fn apply<F, R, Req>(self, f: F) -> Apply<Self, F, R, Req>
|
||||||
where
|
where
|
||||||
|
@ -32,6 +34,15 @@ pub trait ServiceExt: Service {
|
||||||
Apply::new(f, self)
|
Apply::new(f, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call another service after call to this one has resolved successfully.
|
||||||
|
///
|
||||||
|
/// This function can be used to chain two services together and ensure that
|
||||||
|
/// the second service isn't called until call to the fist service have
|
||||||
|
/// finished. Result of the call to the first service is used as an
|
||||||
|
/// input parameter for the second service's call.
|
||||||
|
///
|
||||||
|
/// Note that this function consumes the receiving service and returns a
|
||||||
|
/// wrapped version of it.
|
||||||
fn and_then<F, B>(self, service: F) -> AndThen<Self, B>
|
fn and_then<F, B>(self, service: F) -> AndThen<Self, B>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
@ -41,6 +52,11 @@ pub trait ServiceExt: Service {
|
||||||
AndThen::new(self, service.into_service())
|
AndThen::new(self, service.into_service())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map this service's error to any error implementing `From` for
|
||||||
|
/// this service`s `Error`.
|
||||||
|
///
|
||||||
|
/// Note that this function consumes the receiving service and returns a
|
||||||
|
/// wrapped version of it.
|
||||||
fn from_err<E>(self) -> FromErr<Self, E>
|
fn from_err<E>(self) -> FromErr<Self, E>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
@ -49,6 +65,15 @@ pub trait ServiceExt: Service {
|
||||||
FromErr::new(self)
|
FromErr::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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<F, R>(self, f: F) -> Map<Self, F, R>
|
fn map<F, R>(self, f: F) -> Map<Self, F, R>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
@ -57,6 +82,14 @@ pub trait ServiceExt: Service {
|
||||||
Map::new(self, f)
|
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. This is useful for example 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<F, E>(self, f: F) -> MapErr<Self, F, E>
|
fn map_err<F, E>(self, f: F) -> MapErr<Self, F, E>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
|
Loading…
Reference in a new issue