From f66d8bcf33530c858a502bfa170f2383a8cbc204 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 29 Jan 2017 16:53:20 -0800 Subject: 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 --- src/value/display.rs | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/value/display.rs (limited to 'src/value') 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(()) + } +} -- cgit v1.2.3