min_http11_core/
method.rs1use crate::error::{Error, Result};
2use std::convert::{TryFrom, TryInto};
3use std::fmt::{Display, Formatter};
4
5const GET: &[u8] = b"GET";
6const HEAD: &[u8] = b"HEAD";
7const POST: &[u8] = b"POST";
8const PUT: &[u8] = b"PUT";
9const DELETE: &[u8] = b"DELETE";
10const OPTIONS: &[u8] = b"OPTIONS";
11const PATCH: &[u8] = b"PATCH";
12
13#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
14pub enum Method {
15 Get,
16 Head,
17 Post,
18 Put,
19 Delete,
20 Options,
21 Patch,
22 Other(&'static [u8]),
23}
24
25impl Method {
26 pub fn as_slice(&self) -> &'static [u8] {
27 self.into()
28 }
29 pub fn from_static(value: &'static [u8]) -> Self {
30 value.try_into().unwrap_or(Method::Other(value))
31 }
32 pub fn can_have_body(&self) -> bool {
33 !matches!(self, Method::Get | Method::Head | Method::Options)
34 }
35}
36
37impl Display for Method {
38 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39 write!(f, "{}", self.as_slice().escape_ascii())
40 }
41}
42
43impl<'a, const N: usize> TryFrom<&'a [u8; N]> for Method {
44 type Error = Error;
45
46 fn try_from(value: &'a [u8; N]) -> Result<Self> {
47 value.as_slice().try_into()
48 }
49}
50
51impl<'a> TryFrom<&'a [u8]> for Method {
52 type Error = Error;
53
54 fn try_from(value: &'a [u8]) -> Result<Self> {
55 match value {
56 GET => Ok(Method::Get),
57 HEAD => Ok(Method::Head),
58 POST => Ok(Method::Post),
59 PUT => Ok(Method::Put),
60 DELETE => Ok(Method::Delete),
61 OPTIONS => Ok(Method::Options),
62 PATCH => Ok(Method::Patch),
63 other => Err(Error::UnknownMethod(other.escape_ascii().to_string())),
64 }
65 }
66}
67
68impl From<&Method> for &'static [u8] {
69 fn from(value: &Method) -> Self {
70 match value {
71 Method::Get => GET,
72 Method::Head => HEAD,
73 Method::Post => POST,
74 Method::Put => PUT,
75 Method::Delete => DELETE,
76 Method::Options => OPTIONS,
77 Method::Patch => PATCH,
78 Method::Other(value) => value,
79 }
80 }
81}
82
83impl AsRef<[u8]> for Method {
84 fn as_ref(&self) -> &'static [u8] {
85 self.into()
86 }
87}
88
89impl TryFrom<&str> for Method {
90 type Error = Error;
91
92 fn try_from(value: &str) -> Result<Self> {
93 value.as_bytes().try_into()
94 }
95}
96
97#[cfg(test)]
98mod test {
99 use super::*;
100
101 #[test]
102 fn from_bytes() {
103 assert_eq!(GET.try_into(), Ok(Method::Get));
104 assert_eq!(HEAD.try_into(), Ok(Method::Head));
105 assert_eq!(POST.try_into(), Ok(Method::Post));
106 assert_eq!(PUT.try_into(), Ok(Method::Put));
107 assert_eq!(DELETE.try_into(), Ok(Method::Delete));
108 assert_eq!(OPTIONS.try_into(), Ok(Method::Options));
109 assert_eq!(PATCH.try_into(), Ok(Method::Patch));
110 let unknown: Result<Method> = b"UNKNOWN".try_into();
111 assert!(unknown.is_err());
112 }
113
114 #[test]
115 fn from_str() {
116 assert_eq!("GET".try_into(), Ok(Method::Get));
117 assert_eq!("HEAD".try_into(), Ok(Method::Head));
118 assert_eq!("POST".try_into(), Ok(Method::Post));
119 assert_eq!("PUT".try_into(), Ok(Method::Put));
120 assert_eq!("DELETE".try_into(), Ok(Method::Delete));
121 assert_eq!("OPTIONS".try_into(), Ok(Method::Options));
122 assert_eq!("PATCH".try_into(), Ok(Method::Patch));
123 let unknown: Result<Method> = "UNKNOWN".try_into();
124 assert!(unknown.is_err());
125 }
126
127 #[test]
128 fn as_ref() {
129 assert_eq!(Method::Get.as_ref(), GET);
130 assert_eq!(Method::Head.as_ref(), HEAD);
131 assert_eq!(Method::Post.as_ref(), POST);
132 assert_eq!(Method::Put.as_ref(), PUT);
133 assert_eq!(Method::Delete.as_ref(), DELETE);
134 assert_eq!(Method::Options.as_ref(), OPTIONS);
135 assert_eq!(Method::Patch.as_ref(), PATCH);
136 assert_eq!(Method::from_static(b"UNKNOWN").as_ref(), b"UNKNOWN")
137 }
138}