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}