tc_transact/public/
string.rs

1use safecast::{Match, TryCastFrom, TryCastInto};
2
3use tc_value::{TCString, Value};
4use tcgeneric::{Map, PathSegment};
5
6use super::{GetHandler, Handler, PostHandler, Route, StateInstance};
7
8struct RenderHandler<'a> {
9    template: &'a TCString,
10}
11
12impl<'a, State: StateInstance> Handler<'a, State> for RenderHandler<'a>
13where
14    TCString: TryCastFrom<State>,
15{
16    fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b, State::Txn, State>>
17    where
18        'b: 'a,
19    {
20        Some(Box::new(|_txn, value| {
21            Box::pin(async move {
22                let result = if value.matches::<Map<Value>>() {
23                    let data: Map<Value> = value.opt_cast_into().unwrap();
24                    self.template.render(data)
25                } else {
26                    self.template.render(value)
27                };
28
29                result.map(Value::String).map(State::from)
30            })
31        }))
32    }
33
34    fn post<'b>(self: Box<Self>) -> Option<PostHandler<'a, 'b, State::Txn, State>>
35    where
36        'b: 'a,
37    {
38        Some(Box::new(|_txn, params| {
39            Box::pin(async move {
40                let params = params
41                    .into_iter()
42                    .map(|(id, state)| {
43                        let as_string = if state.matches::<TCString>() {
44                            state.opt_cast_into().expect("string")
45                        } else {
46                            TCString::from(format!("{state:?}"))
47                        };
48
49                        (id, Value::String(as_string))
50                    })
51                    .collect::<Map<Value>>();
52
53                self.template
54                    .render(params)
55                    .map(Value::String)
56                    .map(State::from)
57            })
58        }))
59    }
60}
61
62impl<State: StateInstance> Route<State> for TCString
63where
64    TCString: TryCastFrom<State>,
65{
66    fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a, State> + 'a>> {
67        if path.len() != 1 {
68            return None;
69        }
70
71        match path[0].as_str() {
72            "render" => Some(Box::new(RenderHandler { template: self })),
73            _ => None,
74        }
75    }
76}