parent
f1a19a9b1e
commit
4cb50eef77
|
@ -27,6 +27,7 @@ members = [
|
|||
"tower-reconnect",
|
||||
"tower-route",
|
||||
"tower-timeout",
|
||||
"tower-util",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "tower-util"
|
||||
version = "0.1.0"
|
||||
authors = ["Carl Lerche <me@carllerche.com>"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1"
|
||||
tower = { version = "0.1", path = ".." }
|
|
@ -0,0 +1,13 @@
|
|||
# Tower Util
|
||||
|
||||
Additional, generally useful, utilities for working with Tower. Contents from
|
||||
this crate may eventually be moved into `tower` proper. They are kept here until
|
||||
they prove their utility.
|
||||
|
||||
# License
|
||||
|
||||
`tower-timeout` is primarily distributed under the terms of both the MIT license
|
||||
and the Apache License (Version 2.0), with portions covered by various BSD-like
|
||||
licenses.
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
|
@ -0,0 +1,47 @@
|
|||
//! Contains `EitherService` and related types and functions.
|
||||
//!
|
||||
//! See `EitherService` documentation for more details.
|
||||
|
||||
use futures::Poll;
|
||||
use futures::future::Either;
|
||||
use tower::Service;
|
||||
|
||||
/// Combine two different service types into a single type.
|
||||
///
|
||||
/// Both services must be of the same request, response, and error types.
|
||||
/// `EitherService` is useful for handling conditional branching in service
|
||||
/// middleware to different inner service types.
|
||||
pub enum EitherService<A, B> {
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
|
||||
impl<A, B> Service for EitherService<A, B>
|
||||
where A: Service,
|
||||
B: Service<Request = A::Request,
|
||||
Response = A::Response,
|
||||
Error = A::Error>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
type Response = A::Response;
|
||||
type Error = A::Error;
|
||||
type Future = Either<A::Future, B::Future>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
use self::EitherService::*;
|
||||
|
||||
match *self {
|
||||
A(ref mut service) => service.poll_ready(),
|
||||
B(ref mut service) => service.poll_ready(),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, request: Self::Request) -> Self::Future {
|
||||
use self::EitherService::*;
|
||||
|
||||
match *self {
|
||||
A(ref mut service) => Either::A(service.call(request)),
|
||||
B(ref mut service) => Either::B(service.call(request)),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
//! Various utility types and functions that are generally with Tower.
|
||||
|
||||
extern crate futures;
|
||||
extern crate tower;
|
||||
|
||||
pub mod either;
|
||||
pub mod option;
|
||||
mod service_fn;
|
||||
|
||||
pub use either::EitherService;
|
||||
pub use service_fn::NewServiceFn;
|
||||
pub use option::OptionService;
|
|
@ -0,0 +1,77 @@
|
|||
//! Contains `OptionService` and related types and functions.
|
||||
//!
|
||||
//! See `OptionService` documentation for more details.
|
||||
//!
|
||||
use futures::{Future, Poll};
|
||||
use tower::Service;
|
||||
|
||||
/// Optionally forwards requests to an inner service.
|
||||
///
|
||||
/// If the inner service is `None`, `Error::None` is returned as the response.
|
||||
pub struct OptionService<T> {
|
||||
inner: Option<T>,
|
||||
}
|
||||
|
||||
/// Response future returned by `OptionService`.
|
||||
pub struct ResponseFuture<T> {
|
||||
inner: Option<T>,
|
||||
}
|
||||
|
||||
/// Error produced by `OptionService` responding to a request.
|
||||
pub enum Error<T> {
|
||||
Inner(T),
|
||||
None,
|
||||
}
|
||||
|
||||
// ===== impl OptionService =====
|
||||
|
||||
impl<T> OptionService<T> {
|
||||
/// Returns an `OptionService` that forwards requests to `inner`.
|
||||
pub fn some(inner: T) -> Self {
|
||||
OptionService { inner: Some(inner) }
|
||||
}
|
||||
|
||||
/// Returns an `OptionService` that responds to all requests with
|
||||
/// `Error::None`.
|
||||
pub fn none() -> Self {
|
||||
OptionService { inner: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Service for OptionService<T>
|
||||
where T: Service,
|
||||
{
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = Error<T::Error>;
|
||||
type Future = ResponseFuture<T::Future>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
match self.inner {
|
||||
Some(ref mut inner) => inner.poll_ready().map_err(Error::Inner),
|
||||
// None services are always ready
|
||||
None => Ok(().into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, request: Self::Request) -> Self::Future {
|
||||
let inner = self.inner.as_mut().map(|i| i.call(request));
|
||||
ResponseFuture { inner }
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl ResponseFuture =====
|
||||
|
||||
impl<T> Future for ResponseFuture<T>
|
||||
where T: Future,
|
||||
{
|
||||
type Item = T::Item;
|
||||
type Error = Error<T::Error>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.inner {
|
||||
Some(ref mut inner) => inner.poll().map_err(Error::Inner),
|
||||
None => Err(Error::None),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
use futures::{IntoFuture, Poll};
|
||||
use tower::{Service, NewService};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A `NewService` implemented by a closure.
|
||||
pub struct NewServiceFn<T> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
// ===== impl NewServiceFn =====
|
||||
|
||||
impl<T, N> NewServiceFn<T>
|
||||
where T: Fn() -> N,
|
||||
N: Service,
|
||||
{
|
||||
/// Returns a new `NewServiceFn` with the given closure.
|
||||
pub fn new(f: T) -> Self {
|
||||
NewServiceFn { f }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R, S> NewService for NewServiceFn<T>
|
||||
where T: Fn() -> R,
|
||||
R: IntoFuture<Item = S>,
|
||||
S: Service,
|
||||
{
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
type Error = S::Error;
|
||||
type Service = R::Item;
|
||||
type InitError = R::Error;
|
||||
type Future = R::Future;
|
||||
|
||||
fn new_service(&self) -> Self::Future {
|
||||
(self.f)().into_future()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use futures::{future, Future};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
fn f<T>(service: &mut T)
|
||||
where T: Service<Request = u32,
|
||||
Response = Rc<u32>,
|
||||
Error = ()> + Sync
|
||||
{
|
||||
let resp = service.call(123);
|
||||
assert_eq!(*resp.wait().unwrap(), 456);
|
||||
}
|
||||
|
||||
let mut service = ServiceFn::new(|request| {
|
||||
assert_eq!(request, 123);
|
||||
future::ok(Rc::new(456))
|
||||
});
|
||||
|
||||
f(&mut service);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue