finchers_ext/
or.rs

1#![allow(missing_docs)]
2
3use either::Either;
4use finchers_core::endpoint::{Context, Endpoint, IntoEndpoint};
5
6pub fn new<E1, E2>(e1: E1, e2: E2) -> Or<E1::Endpoint, E2::Endpoint>
7where
8    E1: IntoEndpoint,
9    E2: IntoEndpoint<Output = E1::Output>,
10{
11    Or {
12        e1: e1.into_endpoint(),
13        e2: e2.into_endpoint(),
14    }
15}
16
17#[derive(Debug, Copy, Clone)]
18pub struct Or<E1, E2> {
19    e1: E1,
20    e2: E2,
21}
22
23impl<E1, E2> Endpoint for Or<E1, E2>
24where
25    E1: Endpoint,
26    E2: Endpoint<Output = E1::Output>,
27{
28    type Output = E1::Output;
29    type Task = Either<E1::Task, E2::Task>;
30
31    fn apply(&self, cx2: &mut Context) -> Option<Self::Task> {
32        let mut cx1 = cx2.clone();
33        let t1 = self.e1.apply(&mut cx1);
34        let t2 = self.e2.apply(cx2);
35        match (t1, t2) {
36            (Some(t1), Some(t2)) => {
37                // If both endpoints are matched, the one with the larger number of
38                // (consumed) path segments is choosen.
39                let res = if cx1.segments().popped() > cx2.segments().popped() {
40                    *cx2 = cx1;
41                    Either::Left(t1)
42                } else {
43                    Either::Right(t2)
44                };
45                Some(res)
46            }
47            (Some(t1), None) => {
48                *cx2 = cx1;
49                Some(Either::Left(t1))
50            }
51            (None, Some(t2)) => Some(Either::Right(t2)),
52            (None, None) => None,
53        }
54    }
55}