Skip to main content

trillium_handlebars/
handlebars_conn_ext.rs

1use crate::{Assigns, HandlebarsHandler};
2use serde::Serialize;
3use serde_json::json;
4use std::borrow::Cow;
5use trillium::Conn;
6
7/**
8Extension trait that provides handlebar rendering capabilities to
9[`trillium::Conn`]s.
10*/
11pub trait HandlebarsConnExt {
12    /**
13    Registers an "assigns" value on this Conn for use in a template.
14    See example usage at [`Handlebars::new`](crate::Handlebars::new)
15    */
16    fn assign(self, key: impl Into<Cow<'static, str>>, data: impl Serialize) -> Self;
17
18    /**
19    renders a registered template by name with the provided data as
20    assigns. note that this does not use any data accumulated by
21    [`HandlebarsConnExt::assign`]
22
23    ```
24    use trillium_handlebars::{HandlebarsHandler, Handlebars, HandlebarsConnExt};
25    # fn main() -> Result<(), Box<dyn std::error::Error>> {
26
27    #[derive(serde::Serialize)]
28    struct User { name: &'static str };
29
30    let mut handlebars = Handlebars::new();
31    handlebars.register_template_string("greet-user", "Hello {{name}}")?;
32
33    let handler = (
34        HandlebarsHandler::new(handlebars),
35        |mut conn: trillium::Conn| async move {
36            conn.render_with("greet-user", &User { name: "handlebars" })
37        }
38    );
39
40    use trillium_testing::prelude::*;
41    assert_ok!(get("/").on(&handler), "Hello handlebars");
42    # Ok(()) }
43    ```
44    */
45    fn render_with(self, template: &str, data: &impl Serialize) -> Self;
46
47    /**
48    renders a registered template, passing any accumulated assigns to
49    the template. See example at [`Handlebars::new`](crate::Handlebars::new)
50     */
51    fn render(self, template: &str) -> Self;
52
53    /// retrieves a reference to any accumulated assigns on this conn
54    fn assigns(&self) -> Option<&Assigns>;
55
56    /**
57    retrieves a mutable reference to any accumulated assigns on this
58    conn
59     */
60    fn assigns_mut(&mut self) -> &mut Assigns;
61}
62
63impl HandlebarsConnExt for Conn {
64    fn render_with(self, template: &str, data: &impl Serialize) -> Self {
65        let handlebars: &HandlebarsHandler = self
66            .state()
67            .expect("HandlebarsConnExt::render called without running the handler first");
68
69        match handlebars.render(template, data) {
70            Ok(string) => self.ok(string),
71            Err(b) => self.with_status(500).with_body(b.to_string()),
72        }
73    }
74
75    fn assign(mut self, key: impl Into<Cow<'static, str>>, data: impl Serialize) -> Self {
76        self.assigns_mut().insert(
77            key.into(),
78            serde_json::to_value(data).expect("could not serialize assigns"),
79        );
80        self
81    }
82
83    fn render(self, template: &str) -> Self {
84        let handlebars: &HandlebarsHandler = self
85            .state()
86            .expect("HandlebarsConnExt::render called without running the handler first");
87
88        let string = if let Some(assigns) = self.assigns() {
89            handlebars.render(template, assigns)
90        } else {
91            handlebars.render(template, &json!({}))
92        };
93
94        match string {
95            Ok(string) => self.ok(string),
96            Err(b) => self.with_status(500).with_body(b.to_string()),
97        }
98    }
99
100    fn assigns(&self) -> Option<&Assigns> {
101        self.state()
102    }
103
104    fn assigns_mut(&mut self) -> &mut Assigns {
105        self.mut_state_or_insert_with(Assigns::default)
106    }
107}