1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use futures::future::FutureExt;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use crate::{Callback, additional::Additional, Extractor, http::{Response, Request}};
use std::collections::HashSet;
/// Available methods for HTTP Requests
#[derive(Clone, Hash, Debug)]
pub enum Method {
/// Get method
Get,
/// Post method
Post,
/// Put method
Put,
/// Head method
Head,
/// Delete method
Delete,
/// Patch method
Patch,
/// Options method
Options,
/// Trace method
Trace,
/// Connect method
Connect,
/// Custom method
Custom(String)
}
impl std::fmt::Display for Method {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(formatter, "{}", self.to_str())
}
}
impl<A: AsRef<str>> From<A> for Method {
fn from(source: A) -> Method {
match source.as_ref() {
"GET" | "get" => Method::Get,
"POST" | "post" => Method::Post,
"PUT" | "put" => Method::Put,
"HEAD" | "head" => Method::Head,
"DELETE" | "delete" => Method::Delete,
"PATCH" | "patch" => Method::Patch,
"OPTIONS" | "options" => Method::Options,
"TRACE" | "trace" => Method::Trace,
"CONNECT" | "connect" => Method::Connect,
custom => Method::Custom(custom.to_string())
}
}
}
impl PartialEq for Method {
fn eq(&self, other: &Self) -> bool {
self.to_str() == other.to_str()
}
}
impl Eq for Method{}
/// Holds multiple methods to make callback management easier
#[derive(Debug)]
pub struct MultipleMethod(HashSet<Method>);
impl MultipleMethod {
/// Turns the Method into a MethodHandler, which is a short for a tuple Method - Handler
///
/// ```rust
/// # use cataclysm::http::Method;
/// let mul = Method::Put.and(Method::Post).and(Method::Patch);
/// ```
pub fn to<T: Sync, F: Callback<A> + Send + Sync + 'static, A: Extractor<T>>(self, handler: F) -> MethodHandler<T> {
MethodHandler{
methods: self.0,
handler: Box::new(move |req: Request, additional: Arc<Additional<T>>| {
match <A as Extractor<T>>::extract(&req, additional) {
Ok(args) => handler.invoke(args).boxed(),
Err(_e) => {
#[cfg(feature = "full_log")]
log::error!("extractor error: {}", _e);
(async {Response::bad_request()}).boxed()
}
}
})
}
}
/// Adds another method
///
/// ```rust
/// # use cataclysm::http::Method;
/// // This first and belongs to the `Method` struct
/// let mul = Method::Put.and(Method::Post);
/// // This one to the `MultipleMethod` struct
/// let more_mul = mul.and(Method::Patch);
/// ```
pub fn and(mut self, rhs: Method) -> MultipleMethod {
self.0.insert(rhs);
self
}
}
impl Method {
/// Turns the Method into a MethodHandler, which is a short for a tuple Method - Handler
pub fn to<T: Sync, F: Callback<A> + Send + Sync + 'static, A: Extractor<T>>(self, handler: F) -> MethodHandler<T> {
MethodHandler{
methods: vec![self].into_iter().collect(),
handler: Box::new(move |req: Request, additional: Arc<Additional<T>>| {
match <A as Extractor<T>>::extract(&req, additional) {
Ok(args) => handler.invoke(args).boxed(),
Err(_e) => {
#[cfg(feature = "full_log")]
log::error!("extractor error: {}", _e);
(async {Response::bad_request()}).boxed()
}
}
})
}
}
/// Retrieves the `str` representation of a method (all caps).
///
/// ```rust
/// # use cataclysm::http::Method;
/// assert_eq!("GET", Method::Get.to_str());
/// ```
pub fn to_str(&self) -> &str {
match self {
Method::Get => "GET",
Method::Post => "POST",
Method::Put => "PUT",
Method::Head => "HEAD",
Method::Delete => "DELETE",
Method::Patch => "PATCH",
Method::Options => "OPTIONS",
Method::Trace => "TRACE",
Method::Connect => "CONNECT",
Method::Custom(s) => &s
}
}
/// Makes a [MultipleMethod](crate::http::MultipleMethod)
///
/// In case you want a function to reply to more than one method, you can put as many as you want with the `and` method.
/// ```rust
/// # use cataclysm::http::Method;
/// let mul = Method::Get.and(Method::Post);
/// ```
pub fn and(self, rhs: Method) -> MultipleMethod {
MultipleMethod(vec![self, rhs].into_iter().collect())
}
}
/// Contains a group of methods, and a handler function.
pub struct MethodHandler<T = ()> {
pub(crate) methods: HashSet<Method>,
pub(crate) handler: Box<dyn Fn(Request, Arc<Additional<T>>) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync>
}