1use derive_more::Display;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display)]
7pub enum Method {
8 #[display("GET")]
10 Get,
11 #[display("POST")]
13 Post,
14 #[display("PUT")]
16 Put,
17 #[display("DELETE")]
19 Delete,
20 #[display("PATCH")]
22 Patch,
23 #[display("HEAD")]
25 Head,
26 #[display("OPTIONS")]
28 Options,
29}
30
31impl Method {
32 #[must_use]
34 pub const fn is_safe(&self) -> bool {
35 matches!(self, Self::Get | Self::Head | Self::Options)
36 }
37
38 #[must_use]
40 pub const fn is_idempotent(&self) -> bool {
41 matches!(
42 self,
43 Self::Get | Self::Head | Self::Options | Self::Put | Self::Delete
44 )
45 }
46}
47
48impl From<Method> for http::Method {
49 fn from(method: Method) -> Self {
50 match method {
51 Method::Get => Self::GET,
52 Method::Post => Self::POST,
53 Method::Put => Self::PUT,
54 Method::Delete => Self::DELETE,
55 Method::Patch => Self::PATCH,
56 Method::Head => Self::HEAD,
57 Method::Options => Self::OPTIONS,
58 }
59 }
60}
61
62impl TryFrom<http::Method> for Method {
63 type Error = crate::Error;
64
65 fn try_from(method: http::Method) -> Result<Self, Self::Error> {
66 match method {
67 http::Method::GET => Ok(Self::Get),
68 http::Method::POST => Ok(Self::Post),
69 http::Method::PUT => Ok(Self::Put),
70 http::Method::DELETE => Ok(Self::Delete),
71 http::Method::PATCH => Ok(Self::Patch),
72 http::Method::HEAD => Ok(Self::Head),
73 http::Method::OPTIONS => Ok(Self::Options),
74 other => Err(crate::Error::InvalidRequest(format!(
75 "unsupported HTTP method: {other}"
76 ))),
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn method_display() {
87 assert_eq!(Method::Get.to_string(), "GET");
88 assert_eq!(Method::Post.to_string(), "POST");
89 assert_eq!(Method::Put.to_string(), "PUT");
90 assert_eq!(Method::Delete.to_string(), "DELETE");
91 assert_eq!(Method::Patch.to_string(), "PATCH");
92 assert_eq!(Method::Head.to_string(), "HEAD");
93 assert_eq!(Method::Options.to_string(), "OPTIONS");
94 }
95
96 #[test]
97 fn method_is_safe() {
98 assert!(Method::Get.is_safe());
99 assert!(Method::Head.is_safe());
100 assert!(Method::Options.is_safe());
101 assert!(!Method::Post.is_safe());
102 assert!(!Method::Put.is_safe());
103 assert!(!Method::Delete.is_safe());
104 assert!(!Method::Patch.is_safe());
105 }
106
107 #[test]
108 fn method_is_idempotent() {
109 assert!(Method::Get.is_idempotent());
110 assert!(Method::Head.is_idempotent());
111 assert!(Method::Options.is_idempotent());
112 assert!(Method::Put.is_idempotent());
113 assert!(Method::Delete.is_idempotent());
114 assert!(!Method::Post.is_idempotent());
115 assert!(!Method::Patch.is_idempotent());
116 }
117
118 #[test]
119 fn method_into_http() {
120 assert_eq!(http::Method::from(Method::Get), http::Method::GET);
121 assert_eq!(http::Method::from(Method::Post), http::Method::POST);
122 }
123
124 #[test]
125 fn method_from_http() {
126 assert_eq!(
127 Method::try_from(http::Method::GET).expect("GET"),
128 Method::Get
129 );
130 assert_eq!(
131 Method::try_from(http::Method::POST).expect("POST"),
132 Method::Post
133 );
134 }
135}