rama_http/matcher/
method.rs1use crate::{Method, Request};
2use rama_core::extensions::Extensions;
3use std::{
4 fmt,
5 fmt::{Debug, Formatter},
6};
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10pub struct MethodMatcher(u16);
11
12impl MethodMatcher {
13 pub const CONNECT: Self = Self::from_bits(0b0_0000_0001);
15 pub const DELETE: Self = Self::from_bits(0b0_0000_0010);
17 pub const GET: Self = Self::from_bits(0b0_0000_0100);
19 pub const HEAD: Self = Self::from_bits(0b0_0000_1000);
21 pub const OPTIONS: Self = Self::from_bits(0b0_0001_0000);
23 pub const PATCH: Self = Self::from_bits(0b0_0010_0000);
25 pub const POST: Self = Self::from_bits(0b0_0100_0000);
27 pub const PUT: Self = Self::from_bits(0b0_1000_0000);
29 pub const QUERY: Self = Self::from_bits(0b1_0000_0000);
31 pub const TRACE: Self = Self::from_bits(0b10_0000_0000);
33
34 const fn bits(self) -> u16 {
35 let bits = self;
36 bits.0
37 }
38
39 const fn from_bits(bits: u16) -> Self {
40 Self(bits)
41 }
42
43 pub(crate) const NONE: Self = Self::from_bits(0);
45 pub(crate) const ALL_KNOWN: Self = Self::CONNECT
46 .or_method(Self::DELETE)
47 .or_method(Self::GET)
48 .or_method(Self::HEAD)
49 .or_method(Self::OPTIONS)
50 .or_method(Self::PATCH)
51 .or_method(Self::POST)
52 .or_method(Self::PUT)
53 .or_method(Self::QUERY)
54 .or_method(Self::TRACE);
55
56 pub const fn contains(self, other: Self) -> bool {
58 self.bits() & other.bits() == other.bits()
59 }
60
61 #[must_use]
63 pub const fn or_method(self, other: Self) -> Self {
64 Self(self.0 | other.0)
65 }
66
67 #[must_use]
71 pub const fn and_method(self, other: Self) -> Self {
72 Self(self.0 & other.0)
73 }
74
75 #[must_use]
79 pub const fn complement(self) -> Self {
80 Self(Self::ALL_KNOWN.bits() & !self.bits())
81 }
82
83 pub fn iter(self) -> impl Iterator<Item = Method> {
88 [
89 (Self::CONNECT, Method::CONNECT),
90 (Self::DELETE, Method::DELETE),
91 (Self::GET, Method::GET),
92 (Self::HEAD, Method::HEAD),
93 (Self::OPTIONS, Method::OPTIONS),
94 (Self::PATCH, Method::PATCH),
95 (Self::POST, Method::POST),
96 (Self::PUT, Method::PUT),
97 (Self::QUERY, Method::QUERY),
98 (Self::TRACE, Method::TRACE),
99 ]
100 .into_iter()
101 .filter_map(move |(m, method)| self.contains(m).then_some(method))
102 }
103}
104
105impl<Body> rama_core::matcher::Matcher<Request<Body>> for MethodMatcher {
106 fn matches(&self, _ext: Option<&Extensions>, req: &Request<Body>) -> bool {
108 Self::try_from(req.method())
109 .ok()
110 .map(|method| self.contains(method))
111 .unwrap_or_default()
112 }
113}
114
115#[derive(Debug)]
117pub struct NoMatchingMethodMatcher {
118 method: Method,
119}
120
121impl NoMatchingMethodMatcher {
122 pub fn method(&self) -> &Method {
124 &self.method
125 }
126}
127
128impl fmt::Display for NoMatchingMethodMatcher {
129 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
130 write!(f, "no `MethodMatcher` for `{}`", self.method.as_str())
131 }
132}
133
134impl std::error::Error for NoMatchingMethodMatcher {}
135
136impl TryFrom<&Method> for MethodMatcher {
137 type Error = NoMatchingMethodMatcher;
138
139 fn try_from(m: &Method) -> Result<Self, Self::Error> {
140 match m {
141 &Method::CONNECT => Ok(Self::CONNECT),
142 &Method::DELETE => Ok(Self::DELETE),
143 &Method::GET => Ok(Self::GET),
144 &Method::HEAD => Ok(Self::HEAD),
145 &Method::OPTIONS => Ok(Self::OPTIONS),
146 &Method::PATCH => Ok(Self::PATCH),
147 &Method::POST => Ok(Self::POST),
148 &Method::PUT => Ok(Self::PUT),
149 &Method::QUERY => Ok(Self::QUERY),
150 &Method::TRACE => Ok(Self::TRACE),
151 other => Err(Self::Error {
152 method: other.clone(),
153 }),
154 }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn from_http_method() {
164 assert_eq!(
165 MethodMatcher::try_from(&Method::CONNECT).unwrap(),
166 MethodMatcher::CONNECT
167 );
168
169 assert_eq!(
170 MethodMatcher::try_from(&Method::DELETE).unwrap(),
171 MethodMatcher::DELETE
172 );
173
174 assert_eq!(
175 MethodMatcher::try_from(&Method::GET).unwrap(),
176 MethodMatcher::GET
177 );
178
179 assert_eq!(
180 MethodMatcher::try_from(&Method::HEAD).unwrap(),
181 MethodMatcher::HEAD
182 );
183
184 assert_eq!(
185 MethodMatcher::try_from(&Method::OPTIONS).unwrap(),
186 MethodMatcher::OPTIONS
187 );
188
189 assert_eq!(
190 MethodMatcher::try_from(&Method::PATCH).unwrap(),
191 MethodMatcher::PATCH
192 );
193
194 assert_eq!(
195 MethodMatcher::try_from(&Method::POST).unwrap(),
196 MethodMatcher::POST
197 );
198
199 assert_eq!(
200 MethodMatcher::try_from(&Method::PUT).unwrap(),
201 MethodMatcher::PUT
202 );
203
204 assert_eq!(
205 MethodMatcher::try_from(&Method::QUERY).unwrap(),
206 MethodMatcher::QUERY
207 );
208
209 assert_eq!(
210 MethodMatcher::try_from(&Method::TRACE).unwrap(),
211 MethodMatcher::TRACE
212 );
213 }
214
215 #[test]
216 fn query_is_a_known_method() {
217 assert!(MethodMatcher::ALL_KNOWN.contains(MethodMatcher::QUERY));
220 let methods: Vec<_> = MethodMatcher::QUERY.iter().collect();
221 assert_eq!(methods, vec![Method::QUERY]);
222 assert!(MethodMatcher::ALL_KNOWN.iter().any(|m| m == Method::QUERY));
223 }
224}