warp/filter/
and.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use futures_util::ready;
6use pin_project::pin_project;
7
8use super::{Combine, Filter, FilterBase, Internal, Tuple};
9use crate::generic::CombinedTuples;
10use crate::reject::CombineRejection;
11
12#[derive(Clone, Copy, Debug)]
13pub struct And<T, U> {
14    pub(super) first: T,
15    pub(super) second: U,
16}
17
18impl<T, U> FilterBase for And<T, U>
19where
20    T: Filter,
21    T::Extract: Send,
22    U: Filter + Clone + Send,
23    <T::Extract as Tuple>::HList: Combine<<U::Extract as Tuple>::HList> + Send,
24    CombinedTuples<T::Extract, U::Extract>: Send,
25    U::Error: CombineRejection<T::Error>,
26{
27    type Extract = CombinedTuples<T::Extract, U::Extract>;
28    type Error = <U::Error as CombineRejection<T::Error>>::One;
29    type Future = AndFuture<T, U>;
30
31    fn filter(&self, _: Internal) -> Self::Future {
32        AndFuture {
33            state: State::First(self.first.filter(Internal), self.second.clone()),
34        }
35    }
36}
37
38#[allow(missing_debug_implementations)]
39#[pin_project]
40pub struct AndFuture<T: Filter, U: Filter> {
41    #[pin]
42    state: State<T::Future, T::Extract, U>,
43}
44
45#[pin_project(project = StateProj)]
46enum State<T, TE, U: Filter> {
47    First(#[pin] T, U),
48    Second(Option<TE>, #[pin] U::Future),
49    Done,
50}
51
52impl<T, U> Future for AndFuture<T, U>
53where
54    T: Filter,
55    U: Filter,
56    <T::Extract as Tuple>::HList: Combine<<U::Extract as Tuple>::HList> + Send,
57    U::Error: CombineRejection<T::Error>,
58{
59    type Output = Result<
60        CombinedTuples<T::Extract, U::Extract>,
61        <U::Error as CombineRejection<T::Error>>::One,
62    >;
63
64    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
65        self.project().state.poll(cx)
66    }
67}
68
69impl<T, TE, U, E> Future for State<T, TE, U>
70where
71    T: Future<Output = Result<TE, E>>,
72    U: Filter,
73    TE: Tuple,
74    TE::HList: Combine<<U::Extract as Tuple>::HList> + Send,
75    U::Error: CombineRejection<E>,
76{
77    type Output = Result<CombinedTuples<TE, U::Extract>, <U::Error as CombineRejection<E>>::One>;
78
79    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
80        loop {
81            match self.as_mut().project() {
82                StateProj::First(first, second) => {
83                    let ex1 = ready!(first.poll(cx))?;
84                    let fut2 = second.filter(Internal);
85                    self.set(State::Second(Some(ex1), fut2));
86                }
87                StateProj::Second(ex1, second) => {
88                    let ex2 = ready!(second.poll(cx))?;
89                    let ex3 = ex1.take().unwrap().combine(ex2);
90                    self.set(State::Done);
91                    return Poll::Ready(Ok(ex3));
92                }
93                StateProj::Done => panic!("polled after complete"),
94            }
95        }
96    }
97}