Skip to main content

min_http11_core/
method.rs

1use 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}