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
/// The `State` trait, should be replace with trait alias.
pub trait State: 'static + Send + Sync + Sized {}

/// The `Model` trait.
/// The `new_state` method will be called when a request inbound.
///
/// `Model` and its `State` is designed to share data or handler between middlewares.
/// The only one type implemented `Model` by this crate is `()`, you should implement your custom Model if neccassary.
///
/// ### Example
/// ```rust
/// use roa_core::{App, Model};
/// use log::info;
/// use async_std::task::spawn;
/// use http::StatusCode;
///
/// struct AppModel {
///     default_id: u64,
/// }
///
/// struct AppState {
///     id: u64,
/// }
///
/// impl AppModel {
///     fn new() -> Self {
///         Self {
///             default_id: 0,
///         }
///     }
/// }
///
/// impl Model for AppModel {
///     type State = AppState;
///     fn new_state(&self) -> Self::State {
///         AppState {
///             id: self.default_id,
///         }
///     }
/// }
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///     let (addr, server) = App::new(AppModel::new())
///         .gate_fn(|ctx, next| async move {
///             ctx.state_mut().await.id = 1;
///             next().await
///         })
///         .end(|ctx| async move {
///             let id = ctx.state().await.id;
///             assert_eq!(1, id);
///             Ok(())
///         })
///         .run_local()?;
///     spawn(server);
///     let resp = reqwest::get(&format!("http://{}", addr)).await?;
///     assert_eq!(StatusCode::OK, resp.status());
///     Ok(())
/// }
/// ```
pub trait Model: 'static + Send + Sync + Sized {
    /// State type of this model.
    type State: State;

    /// Construct a new state instance.
    fn new_state(&self) -> Self::State;
}

impl Model for () {
    type State = ();
    fn new_state(&self) -> Self::State {}
}

impl<T: 'static + Send + Sync + Sized> State for T {}