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
use error::{Error, Result};
use path::Path;
use render::Chomp;
use htmlescape;
use std::borrow::Borrow;
use std::io::Write;

#[cfg(feature = "serde_json")]
mod json;
#[cfg(feature = "toml")]
mod toml;

pub trait Context<W> {
    fn inject(&self, path: Path, sink: &mut W) -> Result<()>;
    fn iterate(&self, path: Path, chomp: Chomp<W>) -> Result<()>;
}

impl<'a, W, T: Context<W> + ?Sized> Context<W> for &'a T {
    fn inject(&self, path: Path, sink: &mut W) -> Result<()> {
        (*self).inject(path, sink)
    }

    fn iterate(&self, path: Path, chomp: Chomp<W>) -> Result<()> {
        (*self).iterate(path, chomp)
    }
}

impl<W: Write> Context<W> for str {
    fn inject(&self, path: Path, sink: &mut W) -> Result<()> {
        match path.parts().next() {
            Some(_) => Err(Error::Undefined(path.to_owned())),
            None => {
                //TODO: Somehow warn people to only insert stuff as content.
                htmlescape::encode_minimal_w(self, sink)?;
                Ok(())
            },
        }
    }

    fn iterate(&self, path: Path, _: Chomp<W>) -> Result<()> {
        match path.parts().next() {
            Some(_) => Err(Error::Undefined(path.to_owned())),
            None => Err(Error::NotIterable(path.to_owned())),
        }
    }
}

#[derive(Debug)]
pub struct Raw<S>(pub S);

impl<W, S> Context<W> for Raw<S>
where
    S: Borrow<str>,
    W: Write,
{
    fn inject(&self, path: Path, sink: &mut W) -> Result<()> {
        match path.parts().next() {
            Some(_) => Err(Error::Undefined(path.to_owned())),
            None => {
                sink.write_all(self.0.borrow().as_bytes())?;
                Ok(())
            },
        }
    }

    fn iterate(&self, path: Path, _: Chomp<W>) -> Result<()> {
        match path.parts().next() {
            Some(_) => Err(Error::Undefined(path.to_owned())),
            None => Err(Error::NotIterable(path.to_owned())),
        }
    }
}

macro_rules! display_impls {
($($x:ty),*) => {$(
    impl<W: Write> Context<W> for $x {
        fn inject(&self, path: Path, sink: &mut W) -> Result<()> {
            match path.parts().next() {
                Some(_) => Err(Error::Undefined(path.to_owned())),
                None => {
                    write!(sink, "{}", self)?;
                    Ok(())
                },
            }
        }

        fn iterate(&self, path: Path, _: Chomp<W>) -> Result<()> {
            match path.parts().next() {
                Some(_) => Err(Error::Undefined(path.to_owned())),
                None => Err(Error::NotIterable(path.to_owned())),
            }
        }
    }
)*}
}

display_impls! {
    bool,
    i8, i16, i32, i64, isize,
    u8, u16, u32, u64, usize,
    f32, f64
}