Skip to content

Commit

Permalink
add or matcher (web http service)
Browse files Browse the repository at this point in the history
  • Loading branch information
glendc committed Feb 24, 2024
1 parent 0b0de76 commit b4c8177
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 0 deletions.
112 changes: 112 additions & 0 deletions src/http/service/web/matcher/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! matchers to match a request to a web service

mod or_matcher;
pub use or_matcher::{or, Or};

mod method;
pub use method::MethodFilter;

Expand Down Expand Up @@ -40,3 +43,112 @@ macro_rules! impl_matcher_tuple {
}

all_the_tuples_no_last_special_case!(impl_matcher_tuple);

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_matcher_or() {
let m = or!(MethodFilter::GET, MethodFilter::POST);

// ok
assert!(m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder().method("GET").body(()).unwrap()
));
assert!(m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder().method("POST").body(()).unwrap()
));

// not ok
assert!(!m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder().method("PUT").body(()).unwrap()
));
}

#[test]
fn test_matcher_and() {
let m = (MethodFilter::GET, DomainFilter::new("www.example.com"));

// ok
assert!(m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder()
.method("GET")
.uri("http://www.example.com")
.body(())
.unwrap()
));

// not ok
assert!(!m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder()
.method("GET")
.uri("http://example.com")
.body(())
.unwrap()
));
assert!(!m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder()
.method("POST")
.uri("http://www.example.com")
.body(())
.unwrap()
));
}

#[test]
fn test_matcher_and_or() {
let m = or!(
(MethodFilter::GET, DomainFilter::new("www.example.com")),
MethodFilter::POST
);

// ok
assert!(m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder()
.method("GET")
.uri("http://www.example.com")
.body(())
.unwrap()
));
assert!(m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder().method("POST").body(()).unwrap()
));

// not ok
assert!(!m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder()
.method("GET")
.uri("http://example.com")
.body(())
.unwrap()
));
assert!(!m.matches(
&mut Extensions::new(),
&Context::default(),
&Request::builder()
.method("PUT")
.uri("http://www.example.com")
.body(())
.unwrap()
));
}
}
54 changes: 54 additions & 0 deletions src/http/service/web/matcher/or_matcher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use super::Matcher;
use crate::{
http::Request,
service::{context::Extensions, Context},
};

/// A matcher that matches if any of the inner matchers match.
pub struct Or<T>(T);

impl<T: std::fmt::Debug> std::fmt::Debug for Or<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Or").field(&self.0).finish()
}
}

impl<T: Clone> Clone for Or<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}

impl<T> Or<T> {
/// Create a new `Or` matcher.
pub fn new(inner: T) -> Self {
Self(inner)
}
}

macro_rules! impl_or {
($($ty:ident),+ $(,)?) => {
#[allow(non_snake_case)]
impl<State, Body, $($ty),+> Matcher<State, Body> for Or<($($ty),+,)>
where $($ty: Matcher<State, Body>),+
{
fn matches(&self, ext: &mut Extensions, ctx: &Context<State>, req: &Request<Body>) -> bool {
let ($($ty),+,) = &self.0;
$($ty.matches(ext, ctx, req))||+
}
}
};
}

all_the_tuples_no_last_special_case!(impl_or);

#[doc(hidden)]
#[macro_export]
macro_rules! __or {
($($ty:expr),+ $(,)?) => {
$crate::http::service::web::matcher::Or::new(($($ty),+,))
};
}

#[doc(inline)]
pub use __or as or;

0 comments on commit b4c8177

Please sign in to comment.