aboutsummaryrefslogtreecommitdiff
path: root/src/show.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/show.rs')
-rw-r--r--src/show.rs170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/show.rs b/src/show.rs
new file mode 100644
index 0000000..cde4773
--- /dev/null
+++ b/src/show.rs
@@ -0,0 +1,170 @@
+use std::fmt;
+
+use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};
+
+struct Printer<'a, 'b> {
+ output: &'a mut fmt::Formatter<'b>,
+ stack: Vec<&'a str>,
+}
+
+impl fmt::Show for Value {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ String(ref s) => {
+ try!(write!(f, "\""));
+ for ch in s.as_slice().chars() {
+ match ch {
+ '\u0008' => try!(write!(f, "\\b")),
+ '\u0009' => try!(write!(f, "\\t")),
+ '\u000a' => try!(write!(f, "\\n")),
+ '\u000c' => try!(write!(f, "\\f")),
+ '\u000d' => try!(write!(f, "\\r")),
+ '\u0022' => try!(write!(f, "\\\"")),
+ '\u002f' => try!(write!(f, "\\/")),
+ '\u005c' => try!(write!(f, "\\\\")),
+ ch => try!(write!(f, "{}", ch)),
+ }
+ }
+ write!(f, "\"")
+ }
+ Integer(i) => write!(f, "{}", i),
+ Float(fp) => {
+ try!(write!(f, "{}", fp));
+ if fp % 1.0 == 0.0 { try!(write!(f, ".0")) }
+ Ok(())
+ }
+ Boolean(b) => write!(f, "{}", b),
+ Datetime(ref s) => write!(f, "{}", s),
+ Array(ref a) => {
+ match a.as_slice().head() {
+ Some(&Table(..)) => fail!("invalid toml array of tables"),
+ _ => {}
+ }
+ write!(f, "{}", a)
+ }
+ Table(ref t) => {
+ let mut p = Printer { output: f, stack: Vec::new() };
+ p.print(t)
+ }
+ }
+ }
+}
+
+impl<'a, 'b> Printer<'a, 'b> {
+ fn print(&mut self, table: &'a Table) -> fmt::Result {
+ for (k, v) in table.iter() {
+ match *v {
+ Table(..) => continue,
+ Array(ref a) => {
+ match a.as_slice().head() {
+ Some(&Table(..)) => continue,
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ try!(writeln!(self.output, "{} = {}", k, v));
+ }
+ for (k, v) in table.iter() {
+ match *v {
+ Table(ref inner) => {
+ self.stack.push(k.as_slice());
+ try!(writeln!(self.output, "\n[{}]",
+ self.stack.connect(".")));
+ try!(self.print(inner));
+ self.stack.pop();
+ }
+ Array(ref inner) => {
+ match inner.as_slice().head() {
+ Some(&Table(..)) => {}
+ _ => continue
+ }
+ self.stack.push(k.as_slice());
+ for inner in inner.iter() {
+ try!(writeln!(self.output, "\n[[{}]]",
+ self.stack.connect(".")));
+ match *inner {
+ Table(ref inner) => try!(self.print(inner)),
+ _ => fail!("non-heterogeneous toml array"),
+ }
+ }
+ self.stack.pop();
+ }
+ _ => {},
+ }
+ }
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+#[allow(warnings)]
+mod tests {
+ use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};
+ use std::collections::HashMap;
+
+ macro_rules! map( ($($k:expr: $v:expr),*) => ({
+ let mut _m = HashMap::new();
+ $(_m.insert($k.to_str(), $v);)*
+ _m
+ }) )
+
+ #[test]
+ fn simple_show() {
+ assert_eq!(String("foo".to_str()).to_str().as_slice(),
+ "\"foo\"")
+ assert_eq!(Integer(10).to_str().as_slice(),
+ "10")
+ assert_eq!(Float(10.0).to_str().as_slice(),
+ "10.0")
+ assert_eq!(Float(2.4).to_str().as_slice(),
+ "2.4")
+ assert_eq!(Boolean(true).to_str().as_slice(),
+ "true")
+ assert_eq!(Datetime("test".to_str()).to_str().as_slice(),
+ "test")
+ assert_eq!(Array(vec![]).to_str().as_slice(),
+ "[]")
+ assert_eq!(Array(vec![Integer(1), Integer(2)]).to_str().as_slice(),
+ "[1, 2]")
+ }
+
+ #[test]
+ fn table() {
+ assert_eq!(Table(map! { }).to_str().as_slice(),
+ "")
+ assert_eq!(Table(map! { "test": Integer(2) }).to_str().as_slice(),
+ "test = 2\n")
+ assert_eq!(Table(map! {
+ "test": Integer(2),
+ "test2": Table(map! {
+ "test": String("wut".to_str())
+ })
+ }).to_str().as_slice(),
+ "test = 2\n\
+ \n\
+ [test2]\n\
+ test = \"wut\"\n")
+ assert_eq!(Table(map! {
+ "test": Integer(2),
+ "test2": Table(map! {
+ "test": String("wut".to_str())
+ })
+ }).to_str().as_slice(),
+ "test = 2\n\
+ \n\
+ [test2]\n\
+ test = \"wut\"\n")
+ assert_eq!(Table(map! {
+ "test": Integer(2),
+ "test2": Array(vec![Table(map! {
+ "test": String("wut".to_str())
+ })])
+ }).to_str().as_slice(),
+ "test = 2\n\
+ \n\
+ [[test2]]\n\
+ test = \"wut\"\n")
+ }
+}
+