1use crate::std::{boxed::Box, sync::Arc};
14
15use super::extensions::Extensions;
16use crate::Service;
17use crate::extensions::ExtensionsRef;
18use rama_macros::paste;
19use rama_utils::macros::all_the_tuples_no_last_special_case;
20
21pub mod service;
22
23mod op_or;
24#[doc(inline)]
25pub use op_or::Or;
26
27mod op_and;
28#[doc(inline)]
29pub use op_and::And;
30
31mod op_not;
32#[doc(inline)]
33pub use op_not::Not;
34
35mod mfn;
36#[doc(inline)]
37pub use mfn::{MatchFn, match_fn};
38
39mod iter;
40#[doc(inline)]
41pub use iter::IteratorMatcherExt;
42
43mod ext;
44#[doc(inline)]
45pub use ext::ExtensionMatcher;
46
47pub trait Matcher<Input>: Send + Sync + 'static {
50 fn matches(&self, ext: Option<&Extensions>, input: &Input) -> bool;
56
57 fn or<M>(self, other: M) -> impl Matcher<Input>
59 where
60 Self: Sized,
61 M: Matcher<Input>,
62 {
63 Or::new((self, other))
64 }
65
66 fn and<M>(self, other: M) -> impl Matcher<Input>
68 where
69 Self: Sized,
70 M: Matcher<Input>,
71 {
72 And::new((self, other))
73 }
74
75 fn not(self) -> impl Matcher<Input>
77 where
78 Self: Sized,
79 {
80 Not::new(self)
81 }
82}
83
84impl<Input, T> Matcher<Input> for Arc<T>
85where
86 T: Matcher<Input>,
87{
88 fn matches(&self, ext: Option<&Extensions>, input: &Input) -> bool {
89 (**self).matches(ext, input)
90 }
91}
92
93impl<Input, T> Matcher<Input> for &'static T
94where
95 T: Matcher<Input>,
96{
97 #[inline(always)]
98 fn matches(&self, ext: Option<&Extensions>, input: &Input) -> bool {
99 (**self).matches(ext, input)
100 }
101}
102
103impl<Input, T> Matcher<Input> for Option<T>
104where
105 T: Matcher<Input>,
106{
107 fn matches(&self, ext: Option<&Extensions>, input: &Input) -> bool {
108 match self {
109 Some(inner) => inner.matches(ext, input),
110 None => false,
111 }
112 }
113}
114
115impl<Input, T> Matcher<Input> for Box<T>
116where
117 T: Matcher<Input>,
118{
119 fn matches(&self, ext: Option<&Extensions>, input: &Input) -> bool {
120 (**self).matches(ext, input)
121 }
122}
123
124impl<Input> Matcher<Input> for Box<dyn Matcher<Input> + 'static>
125where
126 Input: Send + 'static,
127{
128 fn matches(&self, ext: Option<&Extensions>, input: &Input) -> bool {
129 (**self).matches(ext, input)
130 }
131}
132
133impl<Input> Matcher<Input> for bool {
134 fn matches(&self, _: Option<&Extensions>, _: &Input) -> bool {
135 *self
136 }
137}
138
139macro_rules! impl_matcher_either {
140 ($id:ident, $($param:ident),+ $(,)?) => {
141 impl<$($param),+, Input> Matcher<Input> for crate::combinators::$id<$($param),+>
142 where
143 $($param: Matcher<Input>),+,
144 Input: Send + 'static,
145
146 {
147 fn matches(
148 &self,
149 ext: Option<&Extensions>,
150 input: &Input
151 ) -> bool{
152 match self {
153 $(
154 crate::combinators::$id::$param(layer) => layer.matches(ext, input),
155 )+
156 }
157 }
158 }
159 };
160}
161
162crate::combinators::impl_either!(impl_matcher_either);
163
164#[derive(Debug, Clone)]
167pub struct MatcherRouter<N>(pub N);
168
169macro_rules! impl_matcher_service_tuple {
170 ($($T:ident),+ $(,)?) => {
171 paste!{
172 #[expect(non_camel_case_types)]
173 #[expect(non_snake_case)]
174 impl<$([<M_ $T>], $T),+, S, Input, Output, Error> Service<Input> for MatcherRouter<($(([<M_ $T>], $T)),+, S)>
175 where
176 Input: Send + ExtensionsRef + 'static,
177 Output: Send + 'static,
178 $(
179 [<M_ $T>]: Matcher<Input>,
180 $T: Service<Input, Output = Output, Error = Error>,
181 )+
182 S: Service<Input, Output = Output, Error = Error>,
183 Error: Send + 'static,
184 {
185 type Output = Output;
186 type Error = Error;
187
188 async fn serve(
189 &self,
190 input: Input,
191 ) -> Result<Self::Output, Self::Error> {
192 let ($(([<M_ $T>], $T)),+, S) = &self.0;
193 $(
194 let ext = Extensions::new();
195 if [<M_ $T>].matches(Some(&ext), &input) {
196 input.extensions().extend(&ext);
197 return $T.serve(input).await;
198 }
199 )+
200 S.serve(input).await
201 }
202 }
203 }
204 };
205}
206
207all_the_tuples_no_last_special_case!(impl_matcher_service_tuple);
208
209#[cfg(test)]
210mod test;