Skip to content

Commit

Permalink
Refine Filter::or to propagate Never more eagerly
Browse files Browse the repository at this point in the history
Closes #109
  • Loading branch information
seanmonstar committed Nov 12, 2019
1 parent 54959d6 commit 8e92124
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 22 deletions.
5 changes: 2 additions & 3 deletions src/filter/and.rs
Expand Up @@ -24,7 +24,7 @@ where
U::Error: CombineRejection<T::Error>,
{
type Extract = <<<T::Extract as Tuple>::HList as Combine<<U::Extract as Tuple>::HList>>::Output as HList>::Tuple;
type Error = <U::Error as CombineRejection<T::Error>>::Rejection;
type Error = <U::Error as CombineRejection<T::Error>>::One;
type Future = AndFuture<T, U>;

fn filter(&self) -> Self::Future {
Expand Down Expand Up @@ -52,13 +52,12 @@ impl<T, U> Future for AndFuture<T, U>
where
T: Filter,
U: Filter,
//T::Extract: Combine<U::Extract>,
<T::Extract as Tuple>::HList: Combine<<U::Extract as Tuple>::HList> + Send,
U::Error: CombineRejection<T::Error>,
{
type Output = Result<
<<<T::Extract as Tuple>::HList as Combine<<U::Extract as Tuple>::HList>>::Output as HList>::Tuple,
<U::Error as CombineRejection<T::Error>>::Rejection>;
<U::Error as CombineRejection<T::Error>>::One>;

#[project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Expand Down
4 changes: 2 additions & 2 deletions src/filter/and_then.rs
Expand Up @@ -22,7 +22,7 @@ where
<F::Output as TryFuture>::Error: CombineRejection<T::Error>,
{
type Extract = (<F::Output as TryFuture>::Ok,);
type Error = <<F::Output as TryFuture>::Error as CombineRejection<T::Error>>::Rejection;
type Error = <<F::Output as TryFuture>::Error as CombineRejection<T::Error>>::One;
type Future = AndThenFuture<T, F>;
#[inline]
fn filter(&self) -> Self::Future {
Expand Down Expand Up @@ -66,7 +66,7 @@ where
<F::Output as TryFuture>::Error: CombineRejection<T::Error>,
{
type Output = Result<(<F::Output as TryFuture>::Ok,),
<<F::Output as TryFuture>::Error as CombineRejection<T::Error>>::Rejection>;
<<F::Output as TryFuture>::Error as CombineRejection<T::Error>>::One>;

#[project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Expand Down
4 changes: 2 additions & 2 deletions src/filter/or.rs
Expand Up @@ -23,7 +23,7 @@ where
U::Error: CombineRejection<T::Error>,
{
type Extract = (Either<T::Extract, U::Extract>,);
type Error = <U::Error as CombineRejection<T::Error>>::Rejection;
type Error = <U::Error as CombineRejection<T::Error>>::Combined;
type Future = EitherFuture<T, U>;

fn filter(&self) -> Self::Future {
Expand Down Expand Up @@ -65,7 +65,7 @@ where
U: Filter,
U::Error: CombineRejection<T::Error>,
{
type Output = Result<(Either<T::Extract, U::Extract>,), <U::Error as CombineRejection<T::Error>>::Rejection>;
type Output = Result<(Either<T::Extract, U::Extract>,), <U::Error as CombineRejection<T::Error>>::Combined>;

#[project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Expand Down
6 changes: 3 additions & 3 deletions src/filters/cors.rs
Expand Up @@ -247,7 +247,7 @@ where
F: Filter + Clone + Send + Sync + 'static,
F::Extract: Reply,
F::Error: CombineRejection<Rejection>,
<F::Error as CombineRejection<Rejection>>::Rejection: CombineRejection<Rejection>,
<F::Error as CombineRejection<Rejection>>::One: CombineRejection<Rejection>,
{
type Wrapped = CorsFilter<F>;

Expand Down Expand Up @@ -443,7 +443,7 @@ mod internal {
{
type Extract =
One<Either<One<Preflight>, One<Either<One<Wrapped<F::Extract>>, F::Extract>>>>;
type Error = <F::Error as CombineRejection<Rejection>>::Rejection;
type Error = <F::Error as CombineRejection<Rejection>>::One;
type Future = future::Either<
future::Ready<Result<Self::Extract, Self::Error>>,
WrappedFuture<F::Future>,
Expand Down Expand Up @@ -526,7 +526,7 @@ mod internal {
F: TryFuture,
F::Error: CombineRejection<Rejection>,
{
type Output = Result<One<Either<One<Preflight>, One<Either<One<Wrapped<F::Ok>>, F::Ok>>>>, <F::Error as CombineRejection<Rejection>>::Rejection>;
type Output = Result<One<Either<One<Preflight>, One<Either<One<Wrapped<F::Ok>>, F::Ok>>>>, <F::Error as CombineRejection<Rejection>>::One>;


fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Expand Down
57 changes: 45 additions & 12 deletions src/reject.rs
Expand Up @@ -657,6 +657,9 @@ mod sealed {
use std::convert::Infallible;
use std::fmt;

// This sealed trait exists to allow Filters to return either `Rejection`
// or `Never` (to be replaced with `!`). There are no other types that make
// sense, and so it is sealed.
pub trait Reject: fmt::Debug + Send + Sync {
fn status(&self) -> StatusCode;
fn into_response(&self) -> crate::reply::Response;
Expand All @@ -669,16 +672,43 @@ mod sealed {
fn _assert(_: &dyn Reject) {}
}

// This weird trait is to allow optimizations of propagating when a
// rejection can *never* happen (currently with the `Never` type,
// eventually to be replaced with `!`).
//
// Using this trait means the `Never` gets propagated to chained filters,
// allowing LLVM to eliminate more code paths. Without it, such as just
// requiring that `Rejection::from(Never)` were used in those filters,
// would mean that links later in the chain may assume a rejection *could*
// happen, and no longer eliminate those branches.
pub trait CombineRejection<E>: Send + Sized {
type Rejection: Reject + From<Self> + From<E> + Into<Rejection>;

fn combine(self, other: E) -> Self::Rejection;
/// The type that should be returned when only 1 of the two
/// "rejections" occurs.
///
/// # For example:
///
/// `warp::any().and(warp::path("foo")` has the following steps:
///
/// 1. Since this is `and`, only **one** of the rejections will occur,
/// and as soon as it does, it will be returned.
/// 2. `warp::any()` rejects with `Never`. So, it will never return `Never`.
/// 3. `warp::path()` rejects with `Rejection`. It may return `Rejection`.
///
/// Thus, if the above filter rejects, it will definitely be `Rejection`.
type One: Reject + From<Self> + From<E> + Into<Rejection>;

/// The type that should be returned when both rejections occur,
/// and need to be combined.
type Combined: Reject;

fn combine(self, other: E) -> Self::Combined;
}

impl CombineRejection<Rejection> for Rejection {
type Rejection = Rejection;
type One = Rejection;
type Combined = Rejection;

fn combine(self, other: Rejection) -> Self::Rejection {
fn combine(self, other: Rejection) -> Self::Combined {
let reason = match (self.reason, other.reason) {
(Reason::Other(left), Reason::Other(right)) => {
Reason::Other(Box::new(Rejections::Combined(left, right)))
Expand All @@ -696,25 +726,28 @@ mod sealed {
}

impl CombineRejection<Infallible> for Rejection {
type Rejection = Rejection;
type One = Rejection;
type Combined = Infallible;

fn combine(self, other: Infallible) -> Self::Rejection {
fn combine(self, other: Infallible) -> Self::Combined {
match other {}
}
}

impl CombineRejection<Rejection> for Infallible {
type Rejection = Rejection;
type One = Rejection;
type Combined = Infallible;

fn combine(self, _: Rejection) -> Self::Rejection {
fn combine(self, _: Rejection) -> Self::Combined {
match self {}
}
}

impl CombineRejection<Infallible > for Infallible {
type Rejection = Infallible ;
impl CombineRejection<Infallible> for Infallible {
type One = Infallible;
type Combined = Infallible;

fn combine(self, _: Infallible) -> Self::Rejection {
fn combine(self, _: Infallible) -> Self::Combined {
match self {}
}
}
Expand Down

0 comments on commit 8e92124

Please sign in to comment.