amiya/
context.rs

1use {
2    crate::{Middleware, Request, Response, Result},
3    http_types::Body,
4    std::{borrow::Cow, collections::HashMap, sync::Arc},
5};
6
7/// The context middleware works on.
8#[allow(missing_debug_implementations)]
9pub struct Context<'x, Ex> {
10    /// The incoming http request, without body. You can use [`Context::body`] method to get body.
11    ///
12    /// [`Context::body`]: #method.body
13    pub req: &'x Request,
14    /// The output http response, you can directly edit it
15    pub resp: &'x mut Response,
16    /// User defined extra data
17    pub ex: &'x mut Ex,
18    pub(crate) body: &'x mut Option<Body>,
19    pub(crate) remain_path: &'x str,
20    pub(crate) router_matches: &'x mut HashMap<Cow<'static, str>, String>,
21    pub(crate) tail: &'x [Arc<dyn Middleware<Ex>>],
22}
23
24impl<'x, Ex> Context<'x, Ex>
25where
26    Ex: Send + Sync + 'static,
27{
28    /// Run all inner middleware, this method drives the middleware system.
29    ///
30    /// Notice that you are **not must** call this func in all middleware. if you do not call it
31    /// inner middleware will simply not be executed.
32    ///
33    /// A second call to this method on the same instance will do nothing and directly returns a
34    /// `Ok(())`.
35    ///
36    /// ## Errors
37    ///
38    /// it returns inner middleware execute result.
39    pub async fn next(&mut self) -> Result {
40        if let Some((current, tail)) = self.tail.split_first() {
41            self.tail = tail;
42            let next_ctx = Context {
43                req: self.req,
44                body: self.body,
45                resp: self.resp,
46                ex: self.ex,
47                remain_path: self.remain_path,
48                router_matches: self.router_matches,
49                tail,
50            };
51            current.handle(next_ctx).await
52        } else {
53            Ok(())
54        }
55    }
56
57    /// Get incoming request body data. Only the first call will return `Some`.
58    pub fn body(&mut self) -> Option<Body> {
59        self.body.take()
60    }
61
62    /// The path the next router can match.
63    ///
64    /// It's differ from `Context.req.url().path()`, path returned by this method will only contains
65    /// sub paths that haven't matched by any [`Router`] middleware.
66    ///
67    /// See [`examples/router.rs`] for a example.
68    ///
69    /// [`Router`]: middleware/struct.Router.html
70    /// [`examples/router.rs`]: https://github.com/7sDream/amiya/blob/master/examples/router.rs
71    #[must_use]
72    pub fn path(&self) -> &str {
73        self.remain_path
74    }
75
76    /// The path argument of `name`.
77    ///
78    /// Will be set if a router's any item `{name}` is matched.
79    ///
80    /// See *[Router - Any Item]* for more detail.
81    ///
82    /// ## Examples
83    ///
84    /// See [`examples/arg.rs`] for a example.
85    ///
86    /// [Router - Any Item]: middleware/struct.Router.html#any-item
87    /// [`examples/arg.rs`]: https://github.com/7sDream/amiya/blob/master/examples/arg.rs
88    pub fn arg<K: AsRef<str>>(&self, name: K) -> Option<&str> {
89        self.router_matches.get(name.as_ref()).map(String::as_str)
90    }
91}