rama_http/matcher/
method.rs1use crate::{Method, Request};
2use rama_core::{context::Extensions, Context};
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 TRACE: Self = Self::from_bits(0b1_0000_0000);
31
32 const fn bits(&self) -> u16 {
33 let bits = self;
34 bits.0
35 }
36
37 const fn from_bits(bits: u16) -> Self {
38 Self(bits)
39 }
40
41 pub(crate) const fn contains(&self, other: Self) -> bool {
42 self.bits() & other.bits() == other.bits()
43 }
44
45 pub const fn or(self, other: Self) -> Self {
47 Self(self.0 | other.0)
48 }
49}
50
51impl<State, Body> rama_core::matcher::Matcher<State, Request<Body>> for MethodMatcher {
52 fn matches(
54 &self,
55 _ext: Option<&mut Extensions>,
56 _ctx: &Context<State>,
57 req: &Request<Body>,
58 ) -> bool {
59 MethodMatcher::try_from(req.method())
60 .ok()
61 .map(|method| self.contains(method))
62 .unwrap_or_default()
63 }
64}
65
66#[derive(Debug)]
68pub struct NoMatchingMethodMatcher {
69 method: Method,
70}
71
72impl NoMatchingMethodMatcher {
73 pub fn method(&self) -> &Method {
75 &self.method
76 }
77}
78
79impl fmt::Display for NoMatchingMethodMatcher {
80 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
81 write!(f, "no `MethodMatcher` for `{}`", self.method.as_str())
82 }
83}
84
85impl std::error::Error for NoMatchingMethodMatcher {}
86
87impl TryFrom<&Method> for MethodMatcher {
88 type Error = NoMatchingMethodMatcher;
89
90 fn try_from(m: &Method) -> Result<Self, Self::Error> {
91 match m {
92 &Method::CONNECT => Ok(MethodMatcher::CONNECT),
93 &Method::DELETE => Ok(MethodMatcher::DELETE),
94 &Method::GET => Ok(MethodMatcher::GET),
95 &Method::HEAD => Ok(MethodMatcher::HEAD),
96 &Method::OPTIONS => Ok(MethodMatcher::OPTIONS),
97 &Method::PATCH => Ok(MethodMatcher::PATCH),
98 &Method::POST => Ok(MethodMatcher::POST),
99 &Method::PUT => Ok(MethodMatcher::PUT),
100 &Method::TRACE => Ok(MethodMatcher::TRACE),
101 other => Err(Self::Error {
102 method: other.clone(),
103 }),
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn from_http_method() {
114 assert_eq!(
115 MethodMatcher::try_from(&Method::CONNECT).unwrap(),
116 MethodMatcher::CONNECT
117 );
118
119 assert_eq!(
120 MethodMatcher::try_from(&Method::DELETE).unwrap(),
121 MethodMatcher::DELETE
122 );
123
124 assert_eq!(
125 MethodMatcher::try_from(&Method::GET).unwrap(),
126 MethodMatcher::GET
127 );
128
129 assert_eq!(
130 MethodMatcher::try_from(&Method::HEAD).unwrap(),
131 MethodMatcher::HEAD
132 );
133
134 assert_eq!(
135 MethodMatcher::try_from(&Method::OPTIONS).unwrap(),
136 MethodMatcher::OPTIONS
137 );
138
139 assert_eq!(
140 MethodMatcher::try_from(&Method::PATCH).unwrap(),
141 MethodMatcher::PATCH
142 );
143
144 assert_eq!(
145 MethodMatcher::try_from(&Method::POST).unwrap(),
146 MethodMatcher::POST
147 );
148
149 assert_eq!(
150 MethodMatcher::try_from(&Method::PUT).unwrap(),
151 MethodMatcher::PUT
152 );
153
154 assert_eq!(
155 MethodMatcher::try_from(&Method::TRACE).unwrap(),
156 MethodMatcher::TRACE
157 );
158 }
159}