1use std::io;
10use std::collections::BTreeMap;
11use super::value::Value;
12
13
14pub trait Formatter {
15 fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
16 where W: io::Write;
17 fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
18 where W: io::Write;
19 fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
20 where W: io::Write;
21 fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
22 where W: io::Write;
23}
24
25
26pub struct CompactFormatter;
27
28impl Formatter for CompactFormatter {
29 fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
30 where W: io::Write
31 {
32 writer.write_all(&[ch])
33 }
34
35 fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
36 where W: io::Write
37 {
38 writer.write_all(&[ch])
39 }
40
41 fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
42 where W: io::Write
43 {
44 match *next {
45 Value::Dict(_) | Value::List(_) => Ok(()),
46 _ => writer.write_all(b":"),
47 }
48 }
49
50 fn item_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
51 where W: io::Write
52 {
53 match *next {
54 Value::Dict(_) | Value::List(_) => Ok(()),
55 _ => writer.write_all(b","),
56 }
57 }
58}
59
60
61pub struct PrettyFormatter {
62 indent: usize,
63}
64
65impl PrettyFormatter {
66 fn new() -> Self {
67 PrettyFormatter { indent: 0 }
68 }
69}
70
71#[inline]
72fn indent<W>(writer: &mut W, indent: usize) -> io::Result<()>
73 where W: io::Write
74{
75 for _ in 0..indent {
76 try!(writer.write_all(b" "));
77 }
78 Ok(())
79}
80
81impl Formatter for PrettyFormatter {
82 fn start_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
83 where W: io::Write
84 {
85 self.indent += 1;
86 try!(writer.write_all(&[ch, b'\n']));
87 indent(writer, self.indent)
88 }
89
90 fn end_compound<W>(&mut self, writer: &mut W, ch: u8) -> io::Result<()>
91 where W: io::Write
92 {
93 self.indent -= 1;
94 try!(writer.write(b"\n"));
95 try!(indent(writer, self.indent));
96 writer.write_all(&[ch])
97 }
98
99 fn key_separator<W>(&mut self, writer: &mut W, next: &Value) -> io::Result<()>
100 where W: io::Write
101 {
102 match *next {
103 Value::Dict(_) | Value::List(_) => writer.write_all(b" "),
104 _ => writer.write_all(b": "),
105 }
106 }
107
108 fn item_separator<W>(&mut self, writer: &mut W, _next: &Value) -> io::Result<()>
109 where W: io::Write
110 {
111 try!(writer.write(b"\n"));
112 indent(writer, self.indent)
113 }
114}
115
116
117pub struct Writer<W, F=PrettyFormatter> {
118 writer: W,
119 format: F,
120}
121
122
123impl<W> Writer<W, CompactFormatter>
124 where W: io::Write
125{
126 #[inline]
127 pub fn compact(writer: W) -> Self {
128 Writer::with_formatter(writer, CompactFormatter)
129 }
130}
131
132impl<W> Writer<W>
133 where W: io::Write
134{
135 #[inline]
136 pub fn pretty(writer: W) -> Self {
137 Writer::with_formatter(writer, PrettyFormatter::new())
138 }
139}
140
141impl<W, F> Writer<W, F>
142 where W: io::Write,
143 F: Formatter,
144{
145 #[inline]
146 fn with_formatter(writer: W, formatter: F) -> Self
147 where W: io::Write,
148 F: Formatter,
149 {
150 Writer {
151 writer: writer,
152 format: formatter,
153 }
154 }
155
156 fn write_value(&mut self, value: &Value) -> io::Result<()> {
157 match *value {
158 Value::Bool(value) => self.write_bool(value),
159 Value::Float(value) => self.write_float(value),
160 Value::Integer(value) => self.write_integer(value),
161 Value::String(ref value) => self.write_string(value),
162 Value::List(ref value) => self.write_list(value),
163 Value::Dict(ref value) => self.write_dict(value),
164 }
165 }
166
167 #[inline]
168 fn write_bool(&mut self, value: bool) -> io::Result<()> {
169 if value {
170 self.writer.write_all(b"True")
171 } else {
172 self.writer.write_all(b"False")
173 }
174 }
175
176 #[inline]
177 fn write_float(&mut self, value: f64) -> io::Result<()> {
178 if value.is_nan() || value.is_infinite() {
179 write!(self.writer, "{}", value)
180 } else {
181 let s = format!("{}", value);
182 try!(self.writer.write_all(s.as_bytes()));
183 if !s.contains(".") {
184 try!(self.writer.write_all(b".0"));
185 }
186 Ok(())
187 }
188 }
189
190 #[inline]
191 fn write_integer(&mut self, value: i64) -> io::Result<()> {
192 write!(self.writer, "{}", value)
193 }
194
195 #[inline]
196 fn write_string(&mut self, value: &String) -> io::Result<()> {
197 try!(self.writer.write_all(b"\""));
198 for ch in value.bytes() {
199 try!(match ch {
200 0x09 => self.writer.write_all(b"\\t"),
201 0x0A => self.writer.write_all(b"\\n"),
202 0x0D => self.writer.write_all(b"\\r"),
203 0x22 => self.writer.write_all(b"\\\""),
204 0x5C => self.writer.write_all(b"\\\\"),
205 ch if ch < 0xF => write!(self.writer, "\\0{:X}", ch),
206 ch if ch < 0x20 => write!(self.writer, "\\{:X}", ch),
207 ch => self.writer.write_all(&[ch]),
208 });
209 }
210 self.writer.write_all(b"\"")
211 }
212
213 fn write_list(&mut self, value: &Vec<Value>) -> io::Result<()> {
214 if value.is_empty() {
215 return self.writer.write_all(b"[]");
216 }
217
218 let mut iter = value.iter().peekable();
219 try!(self.format.start_compound(&mut self.writer, b'['));
220 loop {
221 match iter.next() {
222 None => break,
223 Some(value) => {
224 try!(self.write_value(value));
225 match iter.peek () {
226 Some(_) =>
227 try!(self.format.item_separator(&mut self.writer, value)),
228 None => (),
229 }
230 },
231 }
232 }
233 self.format.end_compound(&mut self.writer, b']')
234 }
235
236 #[inline]
237 fn write_dict(&mut self, dict: &BTreeMap<String, Value>) -> io::Result<()> {
238 if dict.is_empty() {
239 return self.writer.write_all(b"{}");
240 }
241
242 try!(self.format.start_compound(&mut self.writer, b'{'));
243 try!(self.write_keyval_items(dict));
244 self.format.end_compound(&mut self.writer, b'}')
245 }
246
247 fn write_keyval_items(&mut self, dict: &BTreeMap<String, Value>) -> io::Result<()> {
248 let mut iter = dict.iter().peekable();
249 loop {
250 match iter.next() {
251 None => break,
252 Some((key, value)) => {
253 try!(self.writer.write_all(key.as_bytes()));
254 try!(self.format.key_separator(&mut self.writer, value));
255 try!(self.write_value(value));
256 match iter.peek () {
257 Some(&(_, ref value)) =>
258 try!(self.format.item_separator(&mut self.writer, value)),
259 None => (),
260 }
261 },
262 }
263 }
264 Ok(())
265 }
266
267 #[inline]
268 pub fn write_message(&mut self, value: &BTreeMap<String, Value>) -> io::Result<()> {
269 self.write_keyval_items(value)
270 }
271
272 #[inline]
273 pub fn write_framed_message(&mut self, value: &BTreeMap<String, Value>) -> io::Result<()> {
274 self.write_dict(value)
275 }
276}
277
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282 use super::super::value::Value;
283 use std::io::Cursor;
284 use std::collections::BTreeMap;
285 use std::f64::{NAN, INFINITY};
286
287 macro_rules! make_write_test {
288 ($name:ident, $value:expr, $pretty:expr, $compact:expr) => {
289 #[test]
290 fn $name() {
291 {
292 println!("Pretty");
293 let mut output = Cursor::new(Vec::new());
294 Writer::pretty(&mut output).write_value($value).ok();
295 assert_eq!($pretty, String::from_utf8(output.into_inner()).unwrap());
296 }
297 {
298 println!("Compact");
299 let mut output = Cursor::new(Vec::new());
300 Writer::compact(&mut output).write_value($value).ok();
301 assert_eq!($compact, String::from_utf8(output.into_inner()).unwrap());
302 }
303 }
304 }
305 }
306
307 make_write_test!(bool_true, &Value::Bool(true), "True", "True");
308 make_write_test!(bool_false, &Value::Bool(false), "False", "False");
309
310 make_write_test!(list_empty, &Value::List(vec![]), "[]", "[]");
311 make_write_test!(list_one, &Value::List(vec![Value::Bool(true)]), "[\n True\n]", "[True]");
312 make_write_test!(list_two, &Value::List(vec![Value::Bool(true), Value::Bool(false)]),
313 "[\n True\n False\n]", "[True,False]");
314 make_write_test!(list_nested,
315 &Value::List(vec![
316 Value::Bool(true),
317 Value::List(vec![Value::Bool(false)])]),
318 "[\n True\n [\n False\n ]\n]", "[True,[False]]");
319
320 make_write_test!(dict_empty, &Value::Dict(BTreeMap::new()), "{}", "{}");
321 make_write_test!(dict_one, &Value::Dict((|| {
322 let mut b = BTreeMap::new();
323 b.insert("item".to_string(), Value::Bool(true));
324 b
325 })()), "{\n item: True\n}", "{item:True}");
326 make_write_test!(dict_two, &Value::Dict((|| {
327 let mut b = BTreeMap::new();
328 b.insert("foo".to_string(), Value::Bool(true));
329 b.insert("bar".to_string(), Value::Bool(false));
330 b
331 })()), "{\n bar: False\n foo: True\n}", "{bar:False,foo:True}");
332
333 macro_rules! make_write_string_tests {
334 ($($name:ident, $value:expr, $expected:expr),+) => {
335 $( make_write_test!($name, &Value::String($value.to_string()), $expected, $expected); )*
336 }
337 }
338
339 make_write_string_tests!(string_empty, "", "\"\"",
340 string_non_empty, "foo bar", "\"foo bar\"",
341 string_unicode, "☺", "\"☺\"",
342 string_escapes, "\n\r\t\\\"", "\"\\n\\r\\t\\\\\\\"\"",
343 string_hexcode, "\0", "\"\\00\"");
344
345
346 macro_rules! make_write_number_tests {
347 ($t:ident, $($name:ident, $value:expr, $expected:expr),+) => {
348 $( make_write_test!($name, &Value::$t($value), $expected, $expected); )*
349 }
350 }
351
352 make_write_number_tests!(Integer,
353 integer_zero, 0, "0",
354 integer_negative, -34, "-34");
355 make_write_number_tests!(Float,
356 float_zero, 0.0, "0.0",
357 float_suffix, 1f64, "1.0",
358 float_positive, 4.5, "4.5",
359 float_negative, -3.2, "-3.2",
360 float_nan, NAN, "NaN",
361 float_infinite, INFINITY, "inf");
362}