maud

The Render trait

By default, a (splice) is rendered using the std::fmt::Display trait, with any HTML special characters escaped automatically.

To change this behavior, implement the Render trait for your type. Then, when a value of this type is used in a template, Maud will call your custom code instead.

Below are some examples of using Render. Feel free to use these snippets in your own project!

Example: a shorthand for including CSS stylesheets

When writing a web page, it can be annoying to write link rel="stylesheet" over and over again. This example provides a shorthand for linking to CSS stylesheets.

use maud::{Markup, Render};

/// Links to a CSS stylesheet at the given path.
struct Css(&'static str);

impl Render for Css {
    fn render(&self) -> Markup {
        html! {
            link rel="stylesheet" type="text/css" href=(self.0);
        }
    }
}

Example: a wrapper that calls std::fmt::Debug

When debugging an application, it can be useful to see its internal state. But these internal data types often don't implement Display. This wrapper lets us use the Debug trait instead.

To avoid extra allocation, we override the .render_to() method instead of .render(). This doesn't do any escaping by default, so we wrap the output in an Escaper as well.

use maud::{Render, Escaper};
use std::fmt;

/// Renders the given value using its `Debug` implementation.
struct Debug<T: fmt::Debug>(T);

impl<T: fmt::Debug> Render for Debug<T> {
    fn render_to(&self, output: &mut String) {
        let mut escaper = Escaper::new(output);
        write!(escaper, "{:?}", self.0).unwrap();
    }
}

Example: rendering Markdown using pulldown-cmark and ammonia

pulldown-cmark is a popular library for converting Markdown to HTML.

We also use the ammonia library, which sanitizes the resulting markup.

extern crate ammonia;
extern crate pulldown_cmark;

use maud::{PreEscaped, Render};
use pulldown_cmark::{Parser, html};

/// Renders a block of Markdown using `pulldown-cmark`.
struct Markdown<T: AsRef<str>>(T);

impl<T: AsRef<str>> Render for Markdown<T> {
    fn render(self, buffer: &mut String) {
        // Generate raw HTML
        let mut unsafe_html = String::new();
        let parser = Parser::new(self.0.as_str());
        html::push_html(&mut unsafe_html, parser);
        // Sanitize it with ammonia
        let safe_html = ammonia::clean(&unsafe_html);
        PreEscaped(safe_html)
    }
}