rama_http/matcher/
version.rsuse crate::{Request, Version};
use rama_core::{context::Extensions, Context};
use std::fmt::{self, Debug, Formatter};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct VersionMatcher(u16);
impl VersionMatcher {
pub const HTTP_09: Self = Self::from_bits(0b0_0000_0010);
pub const HTTP_10: Self = Self::from_bits(0b0_0000_0100);
pub const HTTP_11: Self = Self::from_bits(0b0_0000_1000);
pub const HTTP_2: Self = Self::from_bits(0b0_0001_0000);
pub const HTTP_3: Self = Self::from_bits(0b0_0010_0000);
const fn bits(&self) -> u16 {
let bits = self;
bits.0
}
const fn from_bits(bits: u16) -> Self {
Self(bits)
}
pub(crate) const fn contains(&self, other: Self) -> bool {
self.bits() & other.bits() == other.bits()
}
pub const fn or(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for VersionMatcher {
fn matches(
&self,
_ext: Option<&mut Extensions>,
_ctx: &Context<State>,
req: &Request<Body>,
) -> bool {
VersionMatcher::try_from(req.version())
.ok()
.map(|version| self.contains(version))
.unwrap_or_default()
}
}
#[derive(Debug)]
pub struct NoMatchingVersionMatcher {
version: Version,
}
impl NoMatchingVersionMatcher {
pub fn version(&self) -> &Version {
&self.version
}
}
impl fmt::Display for NoMatchingVersionMatcher {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "no `VersionMatcher` for `{:?}`", self.version)
}
}
impl std::error::Error for NoMatchingVersionMatcher {}
impl TryFrom<Version> for VersionMatcher {
type Error = NoMatchingVersionMatcher;
fn try_from(m: Version) -> Result<Self, Self::Error> {
match m {
Version::HTTP_09 => Ok(VersionMatcher::HTTP_09),
Version::HTTP_10 => Ok(VersionMatcher::HTTP_10),
Version::HTTP_11 => Ok(VersionMatcher::HTTP_11),
Version::HTTP_2 => Ok(VersionMatcher::HTTP_2),
Version::HTTP_3 => Ok(VersionMatcher::HTTP_3),
other => Err(Self::Error { version: other }),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use rama_core::matcher::Matcher;
#[test]
fn test_version_matcher() {
let matcher = VersionMatcher::HTTP_11;
let req = Request::builder()
.version(Version::HTTP_11)
.body(())
.unwrap();
assert!(matcher.matches(None, &Context::default(), &req));
}
#[test]
fn test_version_matcher_any() {
let matcher = VersionMatcher::HTTP_11
.or(VersionMatcher::HTTP_10)
.or(VersionMatcher::HTTP_11);
let req = Request::builder()
.version(Version::HTTP_10)
.body(())
.unwrap();
assert!(matcher.matches(None, &Context::default(), &req));
let req = Request::builder()
.version(Version::HTTP_11)
.body(())
.unwrap();
assert!(matcher.matches(None, &Context::default(), &req));
let req = Request::builder()
.version(Version::HTTP_2)
.body(())
.unwrap();
assert!(!matcher.matches(None, &Context::default(), &req));
}
#[test]
fn test_version_matcher_fail() {
let matcher = VersionMatcher::HTTP_11;
let req = Request::builder()
.version(Version::HTTP_10)
.body(())
.unwrap();
assert!(!matcher.matches(None, &Context::default(), &req));
}
}