aboutsummaryrefslogtreecommitdiff
path: root/src/value
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2017-01-29 16:53:20 -0800
committerAlex Crichton <alex@alexcrichton.com>2017-02-08 21:21:18 -0800
commitf66d8bcf33530c858a502bfa170f2383a8cbc204 (patch)
tree76498b837fc5f1f6ba0a5f53e1b2d85c6638da4d /src/value
parent473908c9722eeedeec1777237a135f582faa78d8 (diff)
downloadmilf-rs-f66d8bcf33530c858a502bfa170f2383a8cbc204.tar.gz
milf-rs-f66d8bcf33530c858a502bfa170f2383a8cbc204.zip
Rewrite crate with serde support from ground up
This commit completely rewrites this crate from the ground up, supporting serde at the lowest levels as I believe serde support was intended to do. This is a major change from the previous versions of this crate, with a summary of changes being: * Serialization directly to TOML is now supported without going through a `Value` first. * Deserialization directly from TOML is now supported without going through a `Value`. Note that due to the TOML format some values still are buffered in intermediate memory, but overall this should be at a minimum now. * The API of `Value` was overhauled to match the API of `serde_json::Value`. The changes here were to: * Add `is_*` accessors * Add `get` and `get_mut` for one-field lookups. * Implement panicking lookups through `Index` The old `index` methods are now gone in favor of `get` and `Index` implementations. * A `Datetime` type has been added to represent a TOML datetime in a first-class fashion. Currently this type provides no accessors other than a `Display` implementation, but the idea is that this will grow support over time for decomposing the date. * Support for the `rustc-serialize` crate has been dropped, that'll stay on the 0.2 and 0.1 release trains. * This crate no longer supports the detection of unused fields, for that though you can use the `serde_ignored` crate on crates.io
Diffstat (limited to 'src/value')
-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(())
+ }
+}