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
pub trait Page<L, E>: serde::Serialize
where
    E: std::fmt::Debug + From<ft_sdk::Error>,
{
    fn page(c: &mut L) -> Result<Self, E>
    where
        Self: Sized;
}

pub trait Action<L, E>
where
    E: std::fmt::Debug + From<ft_sdk::Error>,
{
    fn validate(c: &mut L) -> Result<Self, E>
    where
        Self: Sized;
    fn action(&self, c: &mut L) -> Result<ActionOutput, E>
    where
        Self: Sized;
}

#[derive(Debug)]
pub enum ActionOutput {
    Reload,
    Redirect(String),
    Data(FrontendData),
}

pub type FrontendData = std::collections::HashMap<String, serde_json::Value>;

pub enum RequestType {
    Page,
    Action,
}

pub trait Layout {
    type Error: std::fmt::Debug + From<ft_sdk::Error>;

    fn from_in(in_: ft_sdk::In, ty: RequestType) -> Result<Self, Self::Error>
    where
        Self: Sized;

    fn _page<P>(r: http::Request<bytes::Bytes>) -> Result<http::Response<bytes::Bytes>, Self::Error>
    where
        P: Page<Self, Self::Error> + serde::Serialize,
        Self: Sized,
    {
        let in_ = ft_sdk::In::from_request(r)?;
        let mut l = Self::from_in(in_, RequestType::Page)?;
        let p = P::page(&mut l)?;
        let vj = serde_json::to_value(&p).unwrap();
        let oj = l.json(vj)?;
        Ok(ft_sdk::json_response(oj))
    }

    fn page<P>(r: http::Request<bytes::Bytes>) -> http::Response<bytes::Bytes>
    where
        P: Page<Self, Self::Error> + serde::Serialize,
        Self: Sized,
    {
        match Self::_page::<P>(r) {
            Ok(r) => r,
            Err(e) => Self::render_error(e),
        }
    }
    fn action<A>(r: http::Request<bytes::Bytes>) -> http::Response<bytes::Bytes>
    where
        A: Action<Self, Self::Error>,
        Self: Sized,
    {
        match Self::_action::<A>(r) {
            Ok(r) => r,
            Err(e) => Self::render_error(e),
        }
    }

    fn _action<A>(
        r: http::Request<bytes::Bytes>,
    ) -> Result<http::Response<bytes::Bytes>, Self::Error>
    where
        A: Action<Self, Self::Error>,
        Self: Sized,
    {
        let in_ = ft_sdk::In::from_request(r)?;
        let mut l = Self::from_in(in_, RequestType::Action)?;
        let a = A::validate(&mut l)?;
        let o = a.action(&mut l)?;
        Ok(a2r(o))
    }

    fn json(&mut self, o: serde_json::Value) -> Result<serde_json::Value, Self::Error>;
    fn render_error(e: Self::Error) -> http::Response<bytes::Bytes>;
}

fn a2r(r: ActionOutput) -> http::Response<bytes::Bytes> {
    ft_sdk::json_response(match r {
        ActionOutput::Reload => serde_json::json!({"reload": true}),
        ActionOutput::Redirect(redirect) => serde_json::json!({"redirect": redirect }),
        ActionOutput::Data(data) => serde_json::json!({"data": data}),
    })
}