use either::Either;
use either::Either::*;
use http::Response;
use std::mem;
use endpoint::{ApplyContext, ApplyResult, Endpoint};
use error::Error;
use output::{Output, OutputContext};
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone)]
pub struct Or<E1, E2> {
pub(super) e1: E1,
pub(super) e2: E2,
}
impl<'a, E1, E2> Endpoint<'a> for Or<E1, E2>
where
E1: Endpoint<'a>,
E2: Endpoint<'a>,
{
type Output = (Wrapped<E1::Output, E2::Output>,);
type Future = OrFuture<E1::Future, E2::Future>;
fn apply(&'a self, ecx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
let orig_cursor = ecx.cursor().clone();
match self.e1.apply(ecx) {
Ok(future1) => {
let cursor1 = mem::replace(ecx.cursor(), orig_cursor);
match self.e2.apply(ecx) {
Ok(future2) => {
if cursor1.popped() >= ecx.cursor().popped() {
*ecx.cursor() = cursor1;
Ok(OrFuture::left(future1))
} else {
Ok(OrFuture::right(future2))
}
}
Err(..) => {
*ecx.cursor() = cursor1;
Ok(OrFuture::left(future1))
}
}
}
Err(err1) => {
let _ = mem::replace(ecx.cursor(), orig_cursor);
match self.e2.apply(ecx) {
Ok(future) => Ok(OrFuture::right(future)),
Err(err2) => Err(err1.merge(err2)),
}
}
}
}
}
#[derive(Debug)]
pub struct Wrapped<L, R>(Either<L, R>);
impl<L: Output, R: Output> Output for Wrapped<L, R> {
type Body = Either<L::Body, R::Body>;
type Error = Error;
#[inline(always)]
fn respond(self, cx: &mut OutputContext<'_>) -> Result<Response<Self::Body>, Self::Error> {
self.0.respond(cx)
}
}
#[allow(missing_docs)]
#[derive(Debug)]
pub struct OrFuture<L, R> {
inner: Either<L, R>,
}
impl<L, R> OrFuture<L, R> {
fn left(l: L) -> Self {
OrFuture {
inner: Either::Left(l),
}
}
fn right(r: R) -> Self {
OrFuture {
inner: Either::Right(r),
}
}
}
impl<L, R> ::futures::Future for OrFuture<L, R>
where
L: ::futures::Future<Error = Error>,
R: ::futures::Future<Error = Error>,
{
type Item = (Wrapped<L::Item, R::Item>,);
type Error = Error;
#[inline(always)]
fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {
match self.inner {
Left(ref mut t) => t.poll().map(|t| t.map(|t| (Wrapped(Left(t)),))),
Right(ref mut t) => t.poll().map(|t| t.map(|t| (Wrapped(Right(t)),))),
}
}
}
#[macro_export(local_inner_macros)]
macro_rules! routes {
() => { routes_impl!(@error); };
($h:expr) => { routes_impl!(@error); };
($h:expr,) => { routes_impl!(@error); };
($e1:expr, $e2:expr) => { routes_impl!($e1, $e2); };
($e1:expr, $e2:expr,) => { routes_impl!($e1, $e2); };
($e1:expr, $e2:expr, $($t:expr),*) => { routes_impl!($e1, $e2, $($t),*); };
($e1:expr, $e2:expr, $($t:expr,)+) => { routes_impl!($e1, $e2, $($t),+); };
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! routes_impl {
($e1:expr, $e2:expr, $($t:expr),*) => {{
routes_impl!($e1, routes_impl!($e2, $($t),*))
}};
($e1:expr, $e2:expr) => {{
$crate::endpoint::IntoEndpointExt::or(
$crate::endpoint::IntoEndpoint::into_endpoint($e1),
$crate::endpoint::IntoEndpoint::into_endpoint($e2),
)
}};
(@error) => { compile_error!("The `routes!()` macro requires at least two elements."); };
}