aboutsummaryrefslogtreecommitdiff
path: root/src/value/display.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/value/display.rs')
-rw-r--r--src/value/display.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/value/display.rs b/src/value/display.rs
new file mode 100644
index 0000000..0a6365d
--- /dev/null
+++ b/src/value/display.rs
@@ -0,0 +1,134 @@
+use std::fmt;
+
+use Table as TomlTable;
+use Value::{self, String, Integer, Float, Boolean, Datetime, Array, Table};
+
+struct Printer<'a, 'b:'a> {
+ output: &'a mut fmt::Formatter<'b>,
+ stack: Vec<&'a str>,
+}
+
+struct Key<'a>(&'a [&'a str]);
+
+impl fmt::Display for Value {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ String(ref s) => write_str(f, s),
+ 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),
+ Table(ref t) => {
+ let mut p = Printer { output: f, stack: Vec::new() };
+ p.print(t)
+ }
+ Array(ref a) => {
+ try!(write!(f, "["));
+ for (i, v) in a.iter().enumerate() {
+ if i != 0 { try!(write!(f, ", ")); }
+ try!(write!(f, "{}", v));
+ }
+ write!(f, "]")
+ }
+ }
+ }
+}
+
+fn write_str(f: &mut fmt::Formatter, s: &str) -> fmt::Result {
+ try!(write!(f, "\""));
+ for ch in s.chars() {
+ match ch {
+ '\u{8}' => try!(write!(f, "\\b")),
+ '\u{9}' => try!(write!(f, "\\t")),
+ '\u{a}' => try!(write!(f, "\\n")),
+ '\u{c}' => try!(write!(f, "\\f")),
+ '\u{d}' => try!(write!(f, "\\r")),
+ '\u{22}' => try!(write!(f, "\\\"")),
+ '\u{5c}' => try!(write!(f, "\\\\")),
+ c if c < '\u{1f}' => {
+ try!(write!(f, "\\u{:04}", ch as u32))
+ }
+ ch => try!(write!(f, "{}", ch)),
+ }
+ }
+ write!(f, "\"")
+}
+
+impl<'a, 'b> Printer<'a, 'b> {
+ fn print(&mut self, table: &'a TomlTable) -> fmt::Result {
+ let mut space_out_first = false;
+ for (k, v) in table.iter() {
+ match *v {
+ Table(..) => continue,
+ Array(ref a) => {
+ if let Some(&Table(..)) = a.first() {
+ continue;
+ }
+ }
+ _ => {}
+ }
+ space_out_first = true;
+ try!(writeln!(self.output, "{} = {}", Key(&[k]), v));
+ }
+ for (i, (k, v)) in table.iter().enumerate() {
+ match *v {
+ Table(ref inner) => {
+ self.stack.push(k);
+ if space_out_first || i != 0 {
+ try!(write!(self.output, "\n"));
+ }
+ try!(writeln!(self.output, "[{}]", Key(&self.stack)));
+ try!(self.print(inner));
+ self.stack.pop();
+ }
+ Array(ref inner) => {
+ match inner.first() {
+ Some(&Table(..)) => {}
+ _ => continue
+ }
+ self.stack.push(k);
+ for (j, inner) in inner.iter().enumerate() {
+ if space_out_first || i != 0 || j != 0 {
+ try!(write!(self.output, "\n"));
+ }
+ try!(writeln!(self.output, "[[{}]]", Key(&self.stack)));
+ match *inner {
+ Table(ref inner) => try!(self.print(inner)),
+ _ => panic!("non-heterogeneous toml array"),
+ }
+ }
+ self.stack.pop();
+ }
+ _ => {},
+ }
+ }
+ Ok(())
+ }
+}
+
+impl<'a> fmt::Display for Key<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ for (i, part) in self.0.iter().enumerate() {
+ if i != 0 { try!(write!(f, ".")); }
+ let ok = part.chars().all(|c| {
+ match c {
+ 'a' ... 'z' |
+ 'A' ... 'Z' |
+ '0' ... '9' |
+ '-' | '_' => true,
+ _ => false,
+ }
+ });
+ if ok {
+ try!(write!(f, "{}", part));
+ } else {
+ try!(write_str(f, part));
+ }
+ }
+ Ok(())
+ }
+}