axum/routing/
method_filter.rs1use http::Method;
2use std::{
3 fmt,
4 fmt::{Debug, Formatter},
5};
6
7#[derive(Debug, Copy, Clone, PartialEq)]
9pub struct MethodFilter(u16);
10
11impl MethodFilter {
12 pub const CONNECT: Self = Self::from_bits(0b0_0000_0001);
30 pub const DELETE: Self = Self::from_bits(0b0_0000_0010);
32 pub const GET: Self = Self::from_bits(0b0_0000_0100);
34 pub const HEAD: Self = Self::from_bits(0b0_0000_1000);
36 pub const OPTIONS: Self = Self::from_bits(0b0_0001_0000);
38 pub const PATCH: Self = Self::from_bits(0b0_0010_0000);
40 pub const POST: Self = Self::from_bits(0b0_0100_0000);
42 pub const PUT: Self = Self::from_bits(0b0_1000_0000);
44 pub const TRACE: Self = Self::from_bits(0b1_0000_0000);
46
47 const fn bits(&self) -> u16 {
48 let bits = self;
49 bits.0
50 }
51
52 const fn from_bits(bits: u16) -> Self {
53 Self(bits)
54 }
55
56 pub(crate) const fn contains(&self, other: Self) -> bool {
57 self.bits() & other.bits() == other.bits()
58 }
59
60 #[must_use]
62 pub const fn or(self, other: Self) -> Self {
63 Self(self.0 | other.0)
64 }
65}
66
67#[derive(Debug)]
69pub struct NoMatchingMethodFilter {
70 method: Method,
71}
72
73impl NoMatchingMethodFilter {
74 pub fn method(&self) -> &Method {
76 &self.method
77 }
78}
79
80impl fmt::Display for NoMatchingMethodFilter {
81 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
82 write!(f, "no `MethodFilter` for `{}`", self.method.as_str())
83 }
84}
85
86impl std::error::Error for NoMatchingMethodFilter {}
87
88impl TryFrom<Method> for MethodFilter {
89 type Error = NoMatchingMethodFilter;
90
91 fn try_from(m: Method) -> Result<Self, NoMatchingMethodFilter> {
92 match m {
93 Method::CONNECT => Ok(MethodFilter::CONNECT),
94 Method::DELETE => Ok(MethodFilter::DELETE),
95 Method::GET => Ok(MethodFilter::GET),
96 Method::HEAD => Ok(MethodFilter::HEAD),
97 Method::OPTIONS => Ok(MethodFilter::OPTIONS),
98 Method::PATCH => Ok(MethodFilter::PATCH),
99 Method::POST => Ok(MethodFilter::POST),
100 Method::PUT => Ok(MethodFilter::PUT),
101 Method::TRACE => Ok(MethodFilter::TRACE),
102 other => Err(NoMatchingMethodFilter { method: other }),
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn from_http_method() {
113 assert_eq!(
114 MethodFilter::try_from(Method::CONNECT).unwrap(),
115 MethodFilter::CONNECT
116 );
117
118 assert_eq!(
119 MethodFilter::try_from(Method::DELETE).unwrap(),
120 MethodFilter::DELETE
121 );
122
123 assert_eq!(
124 MethodFilter::try_from(Method::GET).unwrap(),
125 MethodFilter::GET
126 );
127
128 assert_eq!(
129 MethodFilter::try_from(Method::HEAD).unwrap(),
130 MethodFilter::HEAD
131 );
132
133 assert_eq!(
134 MethodFilter::try_from(Method::OPTIONS).unwrap(),
135 MethodFilter::OPTIONS
136 );
137
138 assert_eq!(
139 MethodFilter::try_from(Method::PATCH).unwrap(),
140 MethodFilter::PATCH
141 );
142
143 assert_eq!(
144 MethodFilter::try_from(Method::POST).unwrap(),
145 MethodFilter::POST
146 );
147
148 assert_eq!(
149 MethodFilter::try_from(Method::PUT).unwrap(),
150 MethodFilter::PUT
151 );
152
153 assert_eq!(
154 MethodFilter::try_from(Method::TRACE).unwrap(),
155 MethodFilter::TRACE
156 );
157
158 assert!(
159 MethodFilter::try_from(http::Method::from_bytes(b"CUSTOM").unwrap())
160 .unwrap_err()
161 .to_string()
162 .contains("CUSTOM")
163 );
164 }
165}