rustache/
rustache.rs

1use std::io::Write;
2use compiler;
3use parser;
4use rustc_serialize::json::Json;
5use rustc_serialize::json::Json::{Boolean, Null, I64, U64, F64, Array, Object};
6use rustc_serialize::json::Json::String as JString;
7use build::{HashBuilder, VecBuilder};
8use template::Template;
9use errors::*;
10
11/// Defines a `renderable` trait, so that all of our data is renderable
12pub trait Render {
13    /// `render` function on a `renderable` returns a `reader`
14    fn render<W: Write>(&self, template: &str, writer: &mut W) -> Result<()>;
15}
16
17/// Implement the `renderable` trait on the `HashBuilder` type
18impl<'a> Render for HashBuilder<'a> {
19    fn render<W: Write>(&self, template: &str, writer: &mut W) -> Result<()> {
20        // Create our nodes
21        let tokens = compiler::create_tokens(template);
22        let nodes = parser::parse_nodes(&tokens);
23
24        // Render and write out
25        Template::new().render_data(writer, self, &nodes)
26    }
27}
28
29
30/// Implement the `renderable` trait on the JSON type
31impl Render for Json {
32    fn render<W: Write>(&self, template: &str, writer: &mut W) -> Result<()> {
33        parse_json(self).render(template, writer)
34    }
35}
36
37impl Render for ToString {
38    fn render<W: Write>(&self, template: &str, writer: &mut W) -> Result<()> {
39
40        let json = match Json::from_str(&self.to_string()) {
41            Ok(json) => json,
42            Err(err) => return Err(err.into()),
43        };
44
45        parse_json(&json).render(template, writer)
46    }
47}
48
49// parses a Rust JSON hash and matches all possible types that may be passed in
50// returning a HashBuilder
51fn parse_json(json: &Json) -> HashBuilder {
52    let mut data = HashBuilder::new();
53    for (k, v) in json.as_object().unwrap().iter() {
54        match *v {
55            I64(num) => {
56                data = data.insert(&k[..], num.to_string());
57            }
58            U64(num) => {
59                data = data.insert(&k[..], num.to_string());
60            }
61            F64(num) => {
62                data = data.insert(&k[..], num.to_string());
63            }
64            Boolean(val) => {
65                data = data.insert(&k[..], val);
66            }
67            Array(ref list) => {
68                let mut builder = VecBuilder::new();
69                for item in list.iter() {
70                    builder = match *item {
71                        Object(_) => builder.push(parse_json(item)),
72                        Array(_) => builder.push(parse_json_vector(item)),
73                        JString(_) => builder.push(item.as_string().unwrap()),
74                        Boolean(_) => builder.push(item.as_boolean().unwrap()),
75                        _ => builder,
76                    }
77                }
78                data = data.insert(&k[..], builder);
79            }
80            Object(_) => {
81                data = data.insert(&k[..], parse_json(v));
82            }
83            Null => {}
84            JString(ref text) => {
85                data = data.insert(&k[..], &text[..]);
86            }
87        }
88    }
89
90    data
91}
92
93// parses a Rust JSON vector and matches all possible types that may be passed in
94// returning a VecBuider
95fn parse_json_vector(json: &Json) -> VecBuilder {
96    let mut data = VecBuilder::new();
97    for v in json.as_array().unwrap().iter() {
98        match *v {
99            I64(num) => {
100                data = data.push(num.to_string());
101            }
102            U64(num) => {
103                data = data.push(num.to_string());
104            }
105            F64(num) => {
106                data = data.push(num.to_string());
107            }
108            Boolean(val) => {
109                data = data.push(val);
110            }
111            Array(ref list) => {
112                let mut builder = VecBuilder::new();
113                for item in list.iter() {
114                    builder = match *item {
115                        Object(_) => builder.push(parse_json(item)),
116                        Array(_) => builder.push(parse_json_vector(item)),
117                        JString(_) => builder.push(item.as_string().unwrap()),
118                        Boolean(_) => builder.push(item.as_boolean().unwrap()),
119                        _ => builder,
120                    }
121                }
122                data = data.push(builder);
123            }
124            Object(_) => {
125                data = data.push(parse_json(v));
126            }
127            Null => {}
128            JString(ref text) => {
129                data = data.push(&text[..]);
130            }
131        }
132    }
133    data
134}