mirror of
https://github.com/actix/actix-web.git
synced 2024-12-21 23:56:35 +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};
|
||||
|
||||
/// `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> {
|
||||
a: A,
|
||||
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;
|
||||
|
||||
/// 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>
|
||||
where
|
||||
A: Service,
|
||||
|
@ -73,3 +76,52 @@ where
|
|||
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};
|
||||
|
||||
/// `Map` service combinator
|
||||
pub struct Map<A, F, R> {
|
||||
a: A,
|
||||
/// Service for the `map` combinator, changing the type of a service's response.
|
||||
///
|
||||
/// 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,
|
||||
r: marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<A, F, R> Map<A, F, R>
|
||||
|
@ -17,12 +22,8 @@ where
|
|||
F: Fn(A::Response) -> R,
|
||||
{
|
||||
/// Create new `Map` combinator
|
||||
pub fn new(a: A, f: F) -> Self {
|
||||
Self {
|
||||
a,
|
||||
f,
|
||||
r: marker::PhantomData,
|
||||
}
|
||||
pub fn new(service: A, f: F) -> Self {
|
||||
Self { service, f }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,9 +34,8 @@ where
|
|||
{
|
||||
fn clone(&self) -> Self {
|
||||
Map {
|
||||
a: self.a.clone(),
|
||||
service: self.service.clone(),
|
||||
f: self.f.clone(),
|
||||
r: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,11 +51,11 @@ where
|
|||
type Future = MapFuture<A, F, R>;
|
||||
|
||||
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 {
|
||||
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};
|
||||
|
||||
/// `MapErr` service combinator
|
||||
pub struct MapErr<A, F, E> {
|
||||
a: A,
|
||||
/// Service for the `map_err` combinator, changing the type of a service's
|
||||
/// error.
|
||||
///
|
||||
/// 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,
|
||||
e: marker::PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<A, F, E> MapErr<A, F, E>
|
||||
|
@ -17,12 +23,8 @@ where
|
|||
F: Fn(A::Error) -> E,
|
||||
{
|
||||
/// Create new `MapErr` combinator
|
||||
pub fn new(a: A, f: F) -> Self {
|
||||
Self {
|
||||
a,
|
||||
f,
|
||||
e: marker::PhantomData,
|
||||
}
|
||||
pub fn new(service: A, f: F) -> Self {
|
||||
Self { service, f }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,9 +35,8 @@ where
|
|||
{
|
||||
fn clone(&self) -> Self {
|
||||
MapErr {
|
||||
a: self.a.clone(),
|
||||
service: self.service.clone(),
|
||||
f: self.f.clone(),
|
||||
e: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,11 +53,11 @@ where
|
|||
type Future = MapErrFuture<A, F, E>;
|
||||
|
||||
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 {
|
||||
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_init_err::MapInitErr;
|
||||
|
||||
/// An extension trait for `Service`s that provides a variety of convenient
|
||||
/// adapters
|
||||
pub trait ServiceExt: Service {
|
||||
fn apply<F, R, Req>(self, f: F) -> Apply<Self, F, R, Req>
|
||||
where
|
||||
|
@ -32,6 +34,15 @@ pub trait ServiceExt: Service {
|
|||
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>
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -41,6 +52,11 @@ pub trait ServiceExt: 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>
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -49,6 +65,15 @@ pub trait ServiceExt: Service {
|
|||
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>
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -57,6 +82,14 @@ pub trait ServiceExt: Service {
|
|||
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>
|
||||
where
|
||||
Self: Sized,
|
||||
|
|
Loading…
Reference in a new issue