rama_http/matcher/
version.rs1use crate::{Request, Version};
2use rama_core::extensions::Extensions;
3use std::fmt::{self, Debug, Formatter};
4
5#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
7pub struct VersionMatcher(u16);
8
9impl VersionMatcher {
10 pub const HTTP_09: Self = Self::from_bits(0b0_0000_0010);
12
13 pub const HTTP_10: Self = Self::from_bits(0b0_0000_0100);
15
16 pub const HTTP_11: Self = Self::from_bits(0b0_0000_1000);
18
19 pub const HTTP_2: Self = Self::from_bits(0b0_0001_0000);
21
22 pub const HTTP_3: Self = Self::from_bits(0b0_0010_0000);
24
25 const fn bits(self) -> u16 {
26 let bits = self;
27 bits.0
28 }
29
30 const fn from_bits(bits: u16) -> Self {
31 Self(bits)
32 }
33
34 pub(crate) const fn contains(self, other: Self) -> bool {
35 self.bits() & other.bits() == other.bits()
36 }
37
38 #[must_use]
40 pub const fn or(self, other: Self) -> Self {
41 Self(self.0 | other.0)
42 }
43}
44
45impl<Body> rama_core::matcher::Matcher<Request<Body>> for VersionMatcher {
46 fn matches(&self, _ext: Option<&Extensions>, req: &Request<Body>) -> bool {
48 Self::try_from(req.version())
49 .ok()
50 .map(|version| self.contains(version))
51 .unwrap_or_default()
52 }
53}
54
55#[derive(Debug)]
57pub struct NoMatchingVersionMatcher {
58 version: Version,
59}
60
61impl NoMatchingVersionMatcher {
62 pub fn version(&self) -> &Version {
64 &self.version
65 }
66}
67
68impl fmt::Display for NoMatchingVersionMatcher {
69 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
70 write!(f, "no `VersionMatcher` for `{:?}`", self.version)
71 }
72}
73
74impl std::error::Error for NoMatchingVersionMatcher {}
75
76impl TryFrom<Version> for VersionMatcher {
77 type Error = NoMatchingVersionMatcher;
78
79 fn try_from(m: Version) -> Result<Self, Self::Error> {
80 match m {
81 Version::HTTP_09 => Ok(Self::HTTP_09),
82 Version::HTTP_10 => Ok(Self::HTTP_10),
83 Version::HTTP_11 => Ok(Self::HTTP_11),
84 Version::HTTP_2 => Ok(Self::HTTP_2),
85 Version::HTTP_3 => Ok(Self::HTTP_3),
86 }
87 }
88}
89
90#[cfg(test)]
91mod test {
92 use super::*;
93 use rama_core::matcher::Matcher;
94
95 #[test]
96 fn test_version_matcher() {
97 let matcher = VersionMatcher::HTTP_11;
98 let req = Request::builder()
99 .version(Version::HTTP_11)
100 .body(())
101 .unwrap();
102 assert!(matcher.matches(None, &req));
103 }
104
105 #[test]
106 fn test_version_matcher_any() {
107 let matcher = VersionMatcher::HTTP_11
108 .or(VersionMatcher::HTTP_10)
109 .or(VersionMatcher::HTTP_11);
110
111 let req = Request::builder()
112 .version(Version::HTTP_10)
113 .body(())
114 .unwrap();
115 assert!(matcher.matches(None, &req));
116
117 let req = Request::builder()
118 .version(Version::HTTP_11)
119 .body(())
120 .unwrap();
121 assert!(matcher.matches(None, &req));
122
123 let req = Request::builder()
124 .version(Version::HTTP_2)
125 .body(())
126 .unwrap();
127 assert!(!matcher.matches(None, &req));
128 }
129
130 #[test]
131 fn test_version_matcher_fail() {
132 let matcher = VersionMatcher::HTTP_11;
133 let req = Request::builder()
134 .version(Version::HTTP_10)
135 .body(())
136 .unwrap();
137 assert!(!matcher.matches(None, &req));
138 }
139}