proxima_primitives/pipe/
method.rs1use bytes::Bytes;
2
3#[derive(Clone, Debug, PartialEq, Eq, Default)]
12pub enum Method {
13 #[default]
14 Get,
15 Post,
16 Put,
17 Patch,
18 Delete,
19 Head,
20 Options,
21 Connect,
22 Trace,
23 Other(Bytes),
25}
26
27impl Method {
28 #[must_use]
32 pub fn from_bytes(bytes: &[u8]) -> Self {
33 match bytes {
34 b"GET" => Self::Get,
35 b"POST" => Self::Post,
36 b"PUT" => Self::Put,
37 b"PATCH" => Self::Patch,
38 b"DELETE" => Self::Delete,
39 b"HEAD" => Self::Head,
40 b"OPTIONS" => Self::Options,
41 b"CONNECT" => Self::Connect,
42 b"TRACE" => Self::Trace,
43 other => Self::Other(Bytes::copy_from_slice(other)),
44 }
45 }
46
47 #[must_use]
52 pub fn from_wire(bytes: Bytes) -> Self {
53 match bytes.as_ref() {
54 b"GET" => Self::Get,
55 b"POST" => Self::Post,
56 b"PUT" => Self::Put,
57 b"PATCH" => Self::Patch,
58 b"DELETE" => Self::Delete,
59 b"HEAD" => Self::Head,
60 b"OPTIONS" => Self::Options,
61 b"CONNECT" => Self::Connect,
62 b"TRACE" => Self::Trace,
63 _ => Self::Other(bytes),
64 }
65 }
66
67 #[must_use]
70 pub fn as_bytes(&self) -> &[u8] {
71 match self {
72 Self::Get => b"GET",
73 Self::Post => b"POST",
74 Self::Put => b"PUT",
75 Self::Patch => b"PATCH",
76 Self::Delete => b"DELETE",
77 Self::Head => b"HEAD",
78 Self::Options => b"OPTIONS",
79 Self::Connect => b"CONNECT",
80 Self::Trace => b"TRACE",
81 Self::Other(bytes) => bytes.as_ref(),
82 }
83 }
84
85 #[must_use]
89 pub fn to_bytes(&self) -> Bytes {
90 match self {
91 Self::Get => Bytes::from_static(b"GET"),
92 Self::Post => Bytes::from_static(b"POST"),
93 Self::Put => Bytes::from_static(b"PUT"),
94 Self::Patch => Bytes::from_static(b"PATCH"),
95 Self::Delete => Bytes::from_static(b"DELETE"),
96 Self::Head => Bytes::from_static(b"HEAD"),
97 Self::Options => Bytes::from_static(b"OPTIONS"),
98 Self::Connect => Bytes::from_static(b"CONNECT"),
99 Self::Trace => Bytes::from_static(b"TRACE"),
100 Self::Other(bytes) => Bytes::clone(bytes),
101 }
102 }
103
104 #[must_use]
107 pub fn as_str(&self) -> Option<&str> {
108 core::str::from_utf8(self.as_bytes()).ok()
109 }
110
111 #[must_use]
113 pub fn is_read(&self) -> bool {
114 matches!(self, Self::Get | Self::Head)
115 }
116}
117
118impl From<&[u8]> for Method {
119 fn from(bytes: &[u8]) -> Self {
120 Self::from_bytes(bytes)
121 }
122}
123
124impl From<&str> for Method {
125 fn from(value: &str) -> Self {
126 Self::from_bytes(value.as_bytes())
127 }
128}
129
130impl From<Bytes> for Method {
131 fn from(bytes: Bytes) -> Self {
132 Self::from_wire(bytes)
133 }
134}
135
136impl From<&Bytes> for Method {
137 fn from(bytes: &Bytes) -> Self {
138 Self::from_bytes(bytes.as_ref())
139 }
140}
141
142impl PartialEq<[u8]> for Method {
143 fn eq(&self, other: &[u8]) -> bool {
144 self.as_bytes() == other
145 }
146}
147
148impl PartialEq<&[u8]> for Method {
149 fn eq(&self, other: &&[u8]) -> bool {
150 self.as_bytes() == *other
151 }
152}
153
154impl PartialEq<str> for Method {
155 fn eq(&self, other: &str) -> bool {
156 self.as_bytes() == other.as_bytes()
157 }
158}
159
160impl PartialEq<&str> for Method {
161 fn eq(&self, other: &&str) -> bool {
162 self.as_bytes() == other.as_bytes()
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn standard_methods_parse_to_unit_variants() {
172 assert_eq!(Method::from_bytes(b"GET"), Method::Get);
173 assert_eq!(Method::from(&b"POST"[..]), Method::Post);
174 assert_eq!(Method::from("DELETE"), Method::Delete);
175 }
176
177 #[test]
178 fn from_wire_keeps_unknown_method_zero_copy() {
179 let wire = Bytes::from_static(b"PURGE");
180 let method = Method::from_wire(Bytes::clone(&wire));
181 match method {
183 Method::Other(bytes) => assert_eq!(bytes.as_ptr(), wire.as_ptr()),
184 other => panic!("expected Other, got {other:?}"),
185 }
186 }
187
188 #[test]
189 fn from_wire_standard_drops_bytes_to_unit() {
190 assert_eq!(Method::from_wire(Bytes::from_static(b"PUT")), Method::Put);
191 }
192
193 #[test]
194 fn round_trips_through_wire_bytes() {
195 for raw in [
196 &b"GET"[..],
197 b"POST",
198 b"PUT",
199 b"PATCH",
200 b"DELETE",
201 b"HEAD",
202 b"OPTIONS",
203 b"CONNECT",
204 b"TRACE",
205 b"PURGE",
206 ] {
207 let method = Method::from_bytes(raw);
208 assert_eq!(method.as_bytes(), raw);
209 assert_eq!(method.to_bytes().as_ref(), raw);
210 }
211 }
212
213 #[test]
214 fn standard_to_bytes_is_static_no_alloc() {
215 assert!(matches!(Method::Get.to_bytes(), bytes if bytes.as_ref() == b"GET"));
218 }
219}