1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-22 08:07:18 +00:00

add some doc apis and tests

This commit is contained in:
Nikolay Kim 2018-09-12 13:34:53 -07:00
parent f66eec00e7
commit 62dbe1b001
6 changed files with 299 additions and 29 deletions

View file

@ -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")));
}
}

View file

@ -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", ())));
}
}

View file

@ -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);
}
}

View file

@ -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"));
}
}

View file

@ -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");
}
}

View file

@ -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,