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
102
103
104
105
106
107
use crate::{Assigns, HandlebarsHandler};
use serde::Serialize;
use serde_json::json;
use std::borrow::Cow;
use trillium::Conn;

/**
Extension trait that provides handlebar rendering capabilities to
[`trillium::Conn`]s.
*/
pub trait HandlebarsConnExt {
    /**
    Registers an "assigns" value on this Conn for use in a template.
    See example usage at [`Handlebars::new`](crate::Handlebars::new)
    */
    fn assign(self, key: impl Into<Cow<'static, str>>, data: impl Serialize) -> Self;

    /**
    renders a registered template by name with the provided data as
    assigns. note that this does not use any data accumulated by
    [`HandlebarsConnExt::assign`]

    ```
    use trillium_handlebars::{HandlebarsHandler, Handlebars, HandlebarsConnExt};
    # fn main() -> Result<(), Box<dyn std::error::Error>> {

    #[derive(serde::Serialize)]
    struct User { name: &'static str };

    let mut handlebars = Handlebars::new();
    handlebars.register_template_string("greet-user", "Hello {{name}}")?;

    let handler = (
        HandlebarsHandler::new(handlebars),
        |mut conn: trillium::Conn| async move {
            conn.render_with("greet-user", &User { name: "handlebars" })
        }
    );

    use trillium_testing::prelude::*;
    assert_ok!(get("/").on(&handler), "Hello handlebars");
    # Ok(()) }
    ```
    */
    fn render_with(self, template: &str, data: &impl Serialize) -> Self;

    /**
    renders a registered template, passing any accumulated assigns to
    the template. See example at [`Handlebars::new`](crate::Handlebars::new)
     */
    fn render(self, template: &str) -> Self;

    /// retrieves a reference to any accumulated assigns on this conn
    fn assigns(&self) -> Option<&Assigns>;

    /**
    retrieves a mutable reference to any accumulated assigns on this
    conn
     */
    fn assigns_mut(&mut self) -> &mut Assigns;
}

impl HandlebarsConnExt for Conn {
    fn render_with(self, template: &str, data: &impl Serialize) -> Self {
        let handlebars: &HandlebarsHandler = self
            .state()
            .expect("HandlebarsConnExt::render called without running the handler first");

        match handlebars.render(template, data) {
            Ok(string) => self.ok(string),
            Err(b) => self.with_status(500).with_body(b.to_string()),
        }
    }

    fn assign(mut self, key: impl Into<Cow<'static, str>>, data: impl Serialize) -> Self {
        self.assigns_mut().insert(
            key.into(),
            serde_json::to_value(data).expect("could not serialize assigns"),
        );
        self
    }

    fn render(self, template: &str) -> Self {
        let handlebars: &HandlebarsHandler = self
            .state()
            .expect("HandlebarsConnExt::render called without running the handler first");

        let string = if let Some(assigns) = self.assigns() {
            handlebars.render(template, assigns)
        } else {
            handlebars.render(template, &json!({}))
        };

        match string {
            Ok(string) => self.ok(string),
            Err(b) => self.with_status(500).with_body(b.to_string()),
        }
    }

    fn assigns(&self) -> Option<&Assigns> {
        self.state()
    }

    fn assigns_mut(&mut self) -> &mut Assigns {
        self.mut_state_or_insert_with(Assigns::default)
    }
}