diff options
author | Alex Crichton <alex@alexcrichton.com> | 2017-01-29 16:53:20 -0800 |
---|---|---|
committer | Alex Crichton <alex@alexcrichton.com> | 2017-02-08 21:21:18 -0800 |
commit | f66d8bcf33530c858a502bfa170f2383a8cbc204 (patch) | |
tree | 76498b837fc5f1f6ba0a5f53e1b2d85c6638da4d /src/value | |
parent | 473908c9722eeedeec1777237a135f582faa78d8 (diff) | |
download | milf-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.rs | 134 |
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(()) + } +} |