1use std::any::Any;
2use std::cmp::Ordering;
3use std::collections::{BTreeSet, HashMap};
4use std::fmt::{Debug, Formatter};
5use crate::serializer::{Deserializer, Serializer};
6use crate::request::{Request, Context, Response};
7use dce_util::mixed::DceResult;
8#[cfg(feature = "async")]
9use std::future::Future;
10use std::ops::Deref;
11#[cfg(feature = "async")]
12use std::pin::Pin;
13#[cfg(feature = "async")]
14use async_trait::async_trait;
15use crate::protocol::RoutableProtocol;
16use crate::router::{PATH_PART_SEPARATOR, SUFFIX_BOUNDARY};
17
18
19const SUFFIX_SEPARATOR: char = '|';
20
21
22#[derive(Debug)]
23pub struct Api<Rp, ReqDto, RespDto>
24 where Rp: RoutableProtocol + Send + Sync + Debug + 'static,
25 ReqDto: 'static,
26 RespDto: 'static
27{
28 controller: Controller<Rp, ReqDto, RespDto>,
29 deserializers: Vec<Box<dyn Deserializer<ReqDto> + Send + Sync>>,
33 serializers: Vec<Box<dyn Serializer<RespDto> + Send + Sync>>,
34 method: Option<Box<dyn Method<Rp> + Send + Sync>>,
37 path: &'static str,
38 suffixes: BTreeSet<Suffix>,
39 id: &'static str,
40 omission: bool,
41 redirect: &'static str,
42 name: &'static str,
43 unresponsive: bool,
44 extras: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
47}
48
49impl<Rp, ReqDto, RespDto> Api<Rp, ReqDto, RespDto>
50 where Rp: RoutableProtocol + Debug + Send + Sync + 'static,
51 ReqDto: 'static,
52 RespDto: 'static
53{
54 pub fn new(
55 controller: Controller<Rp, ReqDto, RespDto>,
56 deserializers: Vec<Box<dyn Deserializer<ReqDto> + Send + Sync>>,
57 serializers: Vec<Box<dyn Serializer<RespDto> + Send + Sync>>,
58 method: Option<Box<dyn Method<Rp> + Send + Sync>>,
59 path: &'static str,
60 id: &'static str,
61 omission: bool,
62 redirect: &'static str,
63 name: &'static str,
64 unresponsive: bool,
65 extras: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
66 ) -> Self {
67 let mut path = path.trim_matches(PATH_PART_SEPARATOR);
68 let mut suffixes = BTreeSet::from([Suffix("")]);
69 if let Some(last_part_from) = path.rfind(PATH_PART_SEPARATOR).map_or_else(|| Some(0), |i| Some(i + 1)) {
70 let last_part = &path[last_part_from..];
71 if let Some(bound_index) = last_part.find(SUFFIX_BOUNDARY) {
72 suffixes = last_part[bound_index + 1 ..].split(SUFFIX_SEPARATOR).map(Suffix).collect();
73 path = &path[0.. last_part_from + bound_index];
74 }
75 }
76 Api { controller, deserializers, serializers, method, path, suffixes, id, omission, redirect, name, unresponsive, extras, }
77 }
78
79 pub fn controller(&self) -> &Controller<Rp, ReqDto, RespDto> {
80 &self.controller
81 }
82
83 pub fn deserializers(&self) -> &Vec<Box<dyn Deserializer<ReqDto> + Send + Sync>> {
84 &self.deserializers
85 }
86
87 pub fn serializers(&self) -> &Vec<Box<dyn Serializer<RespDto> + Send + Sync>> {
88 &self.serializers
89 }
90}
91
92#[cfg_attr(feature = "async", async_trait)]
93pub trait ApiTrait<Rp: RoutableProtocol> {
94 fn method(&self) -> &Option<Box<dyn Method<Rp> + Send + Sync>>;
95 fn path(&self) -> &'static str;
96 fn suffixes(&self) -> &BTreeSet<Suffix>;
97 fn id(&self) -> &'static str;
98 fn omission(&self) -> bool;
99 fn redirect(&self) -> &'static str;
100 fn name(&self) -> &'static str;
101 fn unresponsive(&self) -> bool;
102 fn extras(&self) -> &HashMap<&'static str, Box<dyn Any + Send + Sync>>;
103 fn method_match(&self, rp: &Rp) -> bool;
104 #[cfg(feature = "async")]
105 async fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()>;
106 #[cfg(not(feature = "async"))]
107 fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()>;
108}
109
110#[cfg_attr(feature = "async", async_trait)]
111impl<Rp, ReqDto, RespDto> ApiTrait<Rp> for Api<Rp, ReqDto, RespDto>
112 where Rp: RoutableProtocol + Send + Sync + Debug + 'static,
113 ReqDto: 'static,
114 RespDto: 'static
115{
116 fn method(&self) -> &Option<Box<dyn Method<Rp> + Send + Sync>> {
117 &self.method
118 }
119
120 fn path(&self) -> &'static str {
121 self.path
122 }
123
124 fn suffixes(&self) -> &BTreeSet<Suffix> {
125 &self.suffixes
126 }
127
128 fn id(&self) -> &'static str {
129 self.id
130 }
131
132 fn omission(&self) -> bool {
133 self.omission
134 }
135
136 fn redirect(&self) -> &'static str {
137 self.redirect
138 }
139
140 fn name(&self) -> &'static str {
141 self.name
142 }
143
144 fn unresponsive(&self) -> bool {
145 self.unresponsive
146 }
147
148 fn extras(&self) -> &HashMap<&'static str, Box<dyn Any + Send + Sync>> {
149 &self.extras
150 }
151
152 fn method_match(&self, rp: &Rp) -> bool {
153 match &self.method {
154 Some(method) => method.req_match(rp),
155 _ => true
156 }
157 }
158
159 #[cfg(feature = "async")]
160 async fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()> {
161 if context.router().before_controller().is_some() {
162 match context.router().clone().before_controller() {
163 Some(EventHandler::Sync(func)) => func(context)?,
164 Some(EventHandler::Async(func)) => func(context).await?,
165 _ => {},
166 };
167 }
168 let req = Request::new(self, context);
169 *context.rp_mut().resp_mut() = match &self.controller {
170 Controller::Async(controller) => controller(req).await,
171 Controller::Sync(controller) => controller(req),
172 }?;
173 if context.router().after_controller().is_some() {
174 match context.router().clone().after_controller() {
175 Some(EventHandler::Sync(func)) => func(context)?,
176 Some(EventHandler::Async(func)) => func(context).await?,
177 _ => {},
178 };
179 }
180 Ok(())
181 }
182
183 #[cfg(not(feature = "async"))]
184 fn call_controller<'a>(&'static self, context: &'a mut Context<Rp>) -> DceResult<()> {
185 if context.router().before_controller().is_some() {
186 if let Some(EventHandler::Sync(func)) = context.router().clone().before_controller() { func(context)?; }
187 }
188 let req = Request::new(self, context);
189 let Controller::Sync(controller) = &self.controller;
190 *context.rp_mut().resp_mut() = controller(req)?;
191 if context.router().after_controller().is_some() {
192 if let Some(crate::api::EventHandler::Sync(func)) = context.router().clone().after_controller() { func(context)?; }
193 }
194 Ok(())
195 }
196}
197
198impl<Rp: RoutableProtocol> Debug for dyn ApiTrait<Rp> + Send + Sync + 'static {
199 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
200 f.write_str(format!(r#"Api{{method: {:?}, path: "{}", suffixes: {:?}, id: "{}", omission: {}, redirect: "{}", name: "{}", unresponsive: {}, extras: {:?}}}"#,
201 self.method(), self.path(), self.suffixes(), self.id(), self.omission(), self.redirect(), self.name(), self.unresponsive(), self.extras()).as_str())
202 }
203}
204
205
206#[derive(Debug, Clone, Eq, PartialEq)]
207pub struct Suffix(&'static str);
208
209impl Deref for Suffix {
210 type Target = str;
211
212 fn deref(&self) -> &Self::Target {
213 self.0
214 }
215}
216
217impl PartialOrd<Self> for Suffix {
218 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
219 Some(self.cmp(other))
220 }
221}
222
223impl Ord for Suffix {
224 fn cmp(&self, other: &Self) -> Ordering {
225 let compound_diff = self.0.chars().filter(|c| SUFFIX_BOUNDARY.eq_ignore_ascii_case(c)).count() as isize
226 - other.0.chars().filter(|c| SUFFIX_BOUNDARY.eq_ignore_ascii_case(c)).count() as isize;
227 if compound_diff > 0 {
229 return Ordering::Less;
230 } else if compound_diff < 0 {
231 return Ordering::Greater;
232 }
233 self.0.cmp(other.0)
234 }
235}
236
237
238pub trait Method<Rp> {
239 fn to_string(&self) -> String;
240 fn req_match(&self, raw: &Rp) -> bool;
241}
242
243impl<Rp> Debug for dyn Method<Rp> + Send + Sync + 'static {
244 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
245 f.write_str(self.to_string().as_str())
246 }
247}
248
249
250pub enum Controller<Rp, ReqDto, RespDto>
251 where Rp: RoutableProtocol + Debug + Send + Sync + 'static,
252 ReqDto: 'static,
253 RespDto: 'static {
254 Sync(fn(Request<'_, Rp, ReqDto, RespDto>) -> DceResult<Option<Response<Rp::Resp>>>),
255 #[cfg(feature = "async")]
256 Async(Box<dyn Fn(Request<'_, Rp, ReqDto, RespDto>) -> Pin<Box<dyn Future<Output = DceResult<Option<Response<Rp::Resp>>>> + Send + '_>> + Send + Sync>),
257}
258
259impl<Rp, ReqDto, RespDto> Debug for Controller<Rp, ReqDto, RespDto>
260 where Rp: RoutableProtocol + Debug + Send + Sync + 'static,
261 ReqDto: 'static,
262 RespDto: 'static {
263 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
264 formatter.write_str(format!("{} controller", match &self {
265 Controller::Sync(_) => "A sync",
266 #[cfg(feature = "async")]
267 _ => "An async"
268 }).as_str())
269 }
270}
271
272
273pub enum EventHandler<Rp: RoutableProtocol + 'static> {
274 Sync(fn(&mut Context<Rp>) -> DceResult<()>),
275 #[cfg(feature = "async")]
276 Async(Box<dyn for <'a> Fn(&'a mut Context<Rp>) -> Pin<Box<dyn Future<Output = DceResult<()>> + Send + 'a>> + Send + Sync>),
277}
278
279impl<Rp: RoutableProtocol + 'static> Debug for EventHandler<Rp> {
280 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
281 formatter.write_str(format!("{} function", match &self {
282 EventHandler::Sync(_) => "A sync",
283 #[cfg(feature = "async")]
284 _ => "An async"
285 }).as_str())
286 }
287}