use crate::call::Call;
use std::sync::Arc;
pub trait Guard: Send + Sync + 'static {
fn check(&self, call: &Call) -> bool;
}
pub type BoxGuard = Arc<dyn Guard>;
struct HeaderGuard {
name: String,
value: String,
}
impl Guard for HeaderGuard {
fn check(&self, call: &Call) -> bool {
call.header(&self.name) == Some(self.value.as_str())
}
}
pub fn header(name: impl Into<String>, value: impl Into<String>) -> BoxGuard {
Arc::new(HeaderGuard {
name: name.into(),
value: value.into(),
})
}
struct HostGuard(String);
impl Guard for HostGuard {
fn check(&self, call: &Call) -> bool {
call.host().is_some_and(|h| h.eq_ignore_ascii_case(&self.0))
}
}
pub fn host(name: impl Into<String>) -> BoxGuard {
Arc::new(HostGuard(name.into()))
}
struct FnGuard<F>(F);
impl<F: Fn(&Call) -> bool + Send + Sync + 'static> Guard for FnGuard<F> {
fn check(&self, call: &Call) -> bool {
(self.0)(call)
}
}
pub fn fn_guard<F: Fn(&Call) -> bool + Send + Sync + 'static>(f: F) -> BoxGuard {
Arc::new(FnGuard(f))
}
struct All(Vec<BoxGuard>);
impl Guard for All {
fn check(&self, call: &Call) -> bool {
self.0.iter().all(|g| g.check(call))
}
}
pub fn all(guards: Vec<BoxGuard>) -> BoxGuard {
Arc::new(All(guards))
}
struct Any(Vec<BoxGuard>);
impl Guard for Any {
fn check(&self, call: &Call) -> bool {
self.0.iter().any(|g| g.check(call))
}
}
pub fn any(guards: Vec<BoxGuard>) -> BoxGuard {
Arc::new(Any(guards))
}
struct Not(BoxGuard);
impl Guard for Not {
fn check(&self, call: &Call) -> bool {
!self.0.check(call)
}
}
pub fn not(g: BoxGuard) -> BoxGuard {
Arc::new(Not(g))
}