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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Templates in your Rust code.
//!
//! This library allows you to write templates, using macros, mixed in with your
//! Rust code. This allows you to use normal Rust code for the logic, and embed
//! template code along side it.
//!
//! **Caveat**: This library is going to be mostly useful for HTML, primarily
//! because it collapses whitespace (whitespace, including newlines are
//! collapsed into a single space). It also defaults to HTML escaping, though
//! that can be altered by using directives.
//!
//! # Basics
//!
//! The most basic template is this:
//!
//! ```
//! use qtpl::{tplfn, tpl};
//!
//! #[tplfn]
//! fn hello(name: &str) {
//!     tpl! {Hello, {name}!}
//! }
//! ```
//!
//! There are a few things going on here -- first, we're adding the `#[tlpfn]`
//! attribute to our template function. This makes it possible to use this
//! function as a template. Second, we're using the `tpl!` macro inside the body
//! and embedding some textual content. Lastly, we're putting the variable
//! `name` inside another block.
//!
//! # Rendering
//!
//! Fundamentally rendering happens to something that implements
//! `std::io::Write`. This means you could potentially write directly to a
//! socket. Usually you'll buffer the content entirely, or use a buffered socket
//! at the least.
//!
//! ## To a `File`
//! ```
//! # use qtpl::{tplfn, tpl};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, {name}!}
//! # }
//! #
//! let mut file = std::fs::File::create("/tmp/qtpl.txt")?;
//! hello(&mut file, "world")?;
//! #
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! ## To a `Vec<u8>`
//! ```
//! # use qtpl::{tplfn, tpl};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, {name}!}
//! # }
//! #
//! let mut out = vec![];
//! hello(&mut out, "world")?;
//! assert_eq!(out, b"Hello, world!");
//! #
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! ## To a `String` for Testing
//! Purely as a convinience, a `render_string!` macro is provided which
//! panics on errors, and returns a `String`. Remember, this is useful for
//! testing and documentation, but you shouldn't be using this in production
//! code, because it involves unnecessary copies and conversions.
//!
//! ```
//! # use qtpl::{tplfn, tpl, render_string};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, {name}!}
//! # }
//! #
//! assert_eq!(render_string!(hello("world")), "Hello, world!");
//! #
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! # Escaping
//!
//! The default escaping used by the library is geared towards HTML. Using the
//! same example above:
//!
//! ```
//! # use qtpl::{tplfn, tpl, render_string};
//! #
//! # #[tplfn]
//! # fn hello(name: &str) {
//! #     tpl! {Hello, {name}!}
//! # }
//! #
//! assert_eq!(render_string!(hello("<world>")), "Hello, &lt;world&gt;!");
//! #
//! # Ok::<(), std::io::Error>(())
//! ```

pub use qtpl_macros::{child, render_string, tpl, tplfn};
use std::io::{Result, Write};
pub use v_htmlescape::escape;

pub trait Render {
    fn render(self, destination: &mut dyn Write) -> Result<()>;
}

impl<F> Render for F
where
    F: FnOnce(&mut dyn Write) -> Result<()>,
{
    fn render(self, destination: &mut dyn Write) -> Result<()> {
        self(destination)
    }
}