]> git.lizzy.rs Git - rust.git/blob - src/libcore/fmt/builders.rs
f213578c1279b904dc81cebafdeb9ebdc5d995ed
[rust.git] / src / libcore / fmt / builders.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use fmt;
12
13 struct PadAdapter<'a, 'b: 'a> {
14     fmt: &'a mut fmt::Formatter<'b>,
15     on_newline: bool,
16 }
17
18 impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
19     fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
20         PadAdapter {
21             fmt,
22             on_newline: false,
23         }
24     }
25
26     fn as_formatter(&mut self) -> fmt::Formatter {
27         fmt::Formatter {
28             // These only exist in the struct for the `Formatter::run` method,
29             // which won’t be used.
30             curarg: self.fmt.curarg.clone(),
31             args: self.fmt.args,
32
33             // We want to preserve these
34             flags: self.fmt.flags,
35             fill: self.fmt.fill,
36             align: self.fmt.align,
37             width: self.fmt.width,
38             precision: self.fmt.precision,
39
40             // And change this
41             buf: self,
42         }
43     }
44 }
45
46 impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
47     fn write_str(&mut self, mut s: &str) -> fmt::Result {
48         while !s.is_empty() {
49             if self.on_newline {
50                 self.fmt.write_str("    ")?;
51             }
52
53             let split = match s.find('\n') {
54                 Some(pos) => {
55                     self.on_newline = true;
56                     pos + 1
57                 }
58                 None => {
59                     self.on_newline = false;
60                     s.len()
61                 }
62             };
63             self.fmt.write_str(&s[..split])?;
64             s = &s[split..];
65         }
66
67         Ok(())
68     }
69 }
70
71 /// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
72 ///
73 /// This is useful when you wish to output a formatted struct as a part of your
74 /// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
75 ///
76 /// This can be constructed by the
77 /// [`Formatter::debug_struct`](struct.Formatter.html#method.debug_struct)
78 /// method.
79 ///
80 /// # Examples
81 ///
82 /// ```
83 /// use std::fmt;
84 ///
85 /// struct Foo {
86 ///     bar: i32,
87 ///     baz: String,
88 /// }
89 ///
90 /// impl fmt::Debug for Foo {
91 ///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
92 ///         fmt.debug_struct("Foo")
93 ///            .field("bar", &self.bar)
94 ///            .field("baz", &self.baz)
95 ///            .finish()
96 ///     }
97 /// }
98 ///
99 /// // prints "Foo { bar: 10, baz: "Hello World" }"
100 /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() });
101 /// ```
102 #[must_use]
103 #[allow(missing_debug_implementations)]
104 #[stable(feature = "debug_builders", since = "1.2.0")]
105 pub struct DebugStruct<'a, 'b: 'a> {
106     fmt: &'a mut fmt::Formatter<'b>,
107     result: fmt::Result,
108     has_fields: bool,
109 }
110
111 pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
112                                 name: &str)
113                                 -> DebugStruct<'a, 'b> {
114     let result = fmt.write_str(name);
115     DebugStruct {
116         fmt,
117         result,
118         has_fields: false,
119     }
120 }
121
122 impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
123     /// Adds a new field to the generated struct output.
124     #[stable(feature = "debug_builders", since = "1.2.0")]
125     pub fn field(&mut self, name: &str, value: &fmt::Debug) -> &mut DebugStruct<'a, 'b> {
126         self.result = self.result.and_then(|_| {
127             let prefix = if self.has_fields {
128                 ","
129             } else {
130                 " {"
131             };
132
133             if self.is_pretty() {
134                 use fmt::Write;
135                 let mut writer = PadAdapter::new(self.fmt);
136                 writer.write_str(prefix)?;
137                 writer.write_str("\n")?;
138                 writer.write_str(name)?;
139                 writer.write_str(": ")?;
140                 value.fmt(&mut writer.as_formatter())
141             } else {
142                 write!(self.fmt, "{} {}: ", prefix, name)?;
143                 value.fmt(self.fmt)
144             }
145         });
146
147         self.has_fields = true;
148         self
149     }
150
151     /// Finishes output and returns any error encountered.
152     #[stable(feature = "debug_builders", since = "1.2.0")]
153     pub fn finish(&mut self) -> fmt::Result {
154         if self.has_fields {
155             self.result = self.result.and_then(|_| {
156                 if self.is_pretty() {
157                     self.fmt.write_str("\n}")
158                 } else {
159                     self.fmt.write_str(" }")
160                 }
161             });
162         }
163         self.result
164     }
165
166     fn is_pretty(&self) -> bool {
167         self.fmt.alternate()
168     }
169 }
170
171 /// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
172 ///
173 /// This is useful when you wish to output a formatted tuple as a part of your
174 /// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
175 ///
176 /// This can be constructed by the
177 /// [`Formatter::debug_tuple`](struct.Formatter.html#method.debug_tuple)
178 /// method.
179 ///
180 /// # Examples
181 ///
182 /// ```
183 /// use std::fmt;
184 ///
185 /// struct Foo(i32, String);
186 ///
187 /// impl fmt::Debug for Foo {
188 ///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
189 ///         fmt.debug_tuple("Foo")
190 ///            .field(&self.0)
191 ///            .field(&self.1)
192 ///            .finish()
193 ///     }
194 /// }
195 ///
196 /// // prints "Foo(10, "Hello World")"
197 /// println!("{:?}", Foo(10, "Hello World".to_string()));
198 /// ```
199 #[must_use]
200 #[allow(missing_debug_implementations)]
201 #[stable(feature = "debug_builders", since = "1.2.0")]
202 pub struct DebugTuple<'a, 'b: 'a> {
203     fmt: &'a mut fmt::Formatter<'b>,
204     result: fmt::Result,
205     fields: usize,
206     empty_name: bool,
207 }
208
209 pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> {
210     let result = fmt.write_str(name);
211     DebugTuple {
212         fmt,
213         result,
214         fields: 0,
215         empty_name: name.is_empty(),
216     }
217 }
218
219 impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
220     /// Adds a new field to the generated tuple struct output.
221     #[stable(feature = "debug_builders", since = "1.2.0")]
222     pub fn field(&mut self, value: &fmt::Debug) -> &mut DebugTuple<'a, 'b> {
223         self.result = self.result.and_then(|_| {
224             let (prefix, space) = if self.fields > 0 {
225                 (",", " ")
226             } else {
227                 ("(", "")
228             };
229
230             if self.is_pretty() {
231                 use fmt::Write;
232                 let mut writer = PadAdapter::new(self.fmt);
233                 writer.write_str(prefix)?;
234                 writer.write_str("\n")?;
235                 value.fmt(&mut writer.as_formatter())
236             } else {
237                 self.fmt.write_str(prefix)?;
238                 self.fmt.write_str(space)?;
239                 value.fmt(self.fmt)
240             }
241         });
242
243         self.fields += 1;
244         self
245     }
246
247     /// Finishes output and returns any error encountered.
248     #[stable(feature = "debug_builders", since = "1.2.0")]
249     pub fn finish(&mut self) -> fmt::Result {
250         if self.fields > 0 {
251             self.result = self.result.and_then(|_| {
252                 if self.is_pretty() {
253                     self.fmt.write_str("\n")?;
254                 }
255                 if self.fields == 1 && self.empty_name {
256                     self.fmt.write_str(",")?;
257                 }
258                 self.fmt.write_str(")")
259             });
260         }
261         self.result
262     }
263
264     fn is_pretty(&self) -> bool {
265         self.fmt.alternate()
266     }
267 }
268
269 struct DebugInner<'a, 'b: 'a> {
270     fmt: &'a mut fmt::Formatter<'b>,
271     result: fmt::Result,
272     has_fields: bool,
273 }
274
275 impl<'a, 'b: 'a> DebugInner<'a, 'b> {
276     fn entry(&mut self, entry: &fmt::Debug) {
277         self.result = self.result.and_then(|_| {
278             if self.is_pretty() {
279                 use fmt::Write;
280                 let mut writer = PadAdapter::new(self.fmt);
281                 writer.write_str(if self.has_fields {
282                     ",\n"
283                 } else {
284                     "\n"
285                 })?;
286                 entry.fmt(&mut writer.as_formatter())
287             } else {
288                 if self.has_fields {
289                     self.fmt.write_str(", ")?
290                 }
291                 entry.fmt(self.fmt)
292             }
293         });
294
295         self.has_fields = true;
296     }
297
298     pub fn finish(&mut self) {
299         let prefix = if self.is_pretty() && self.has_fields {
300             "\n"
301         } else {
302             ""
303         };
304         self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
305     }
306
307     fn is_pretty(&self) -> bool {
308         self.fmt.alternate()
309     }
310 }
311
312 /// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
313 ///
314 /// This is useful when you wish to output a formatted set of items as a part
315 /// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
316 ///
317 /// This can be constructed by the
318 /// [`Formatter::debug_set`](struct.Formatter.html#method.debug_set)
319 /// method.
320 ///
321 /// # Examples
322 ///
323 /// ```
324 /// use std::fmt;
325 ///
326 /// struct Foo(Vec<i32>);
327 ///
328 /// impl fmt::Debug for Foo {
329 ///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
330 ///         fmt.debug_set().entries(self.0.iter()).finish()
331 ///     }
332 /// }
333 ///
334 /// // prints "{10, 11}"
335 /// println!("{:?}", Foo(vec![10, 11]));
336 /// ```
337 #[must_use]
338 #[allow(missing_debug_implementations)]
339 #[stable(feature = "debug_builders", since = "1.2.0")]
340 pub struct DebugSet<'a, 'b: 'a> {
341     inner: DebugInner<'a, 'b>,
342 }
343
344 pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> {
345     let result = write!(fmt, "{{");
346     DebugSet {
347         inner: DebugInner {
348             fmt,
349             result,
350             has_fields: false,
351         },
352     }
353 }
354
355 impl<'a, 'b: 'a> DebugSet<'a, 'b> {
356     /// Adds a new entry to the set output.
357     #[stable(feature = "debug_builders", since = "1.2.0")]
358     pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugSet<'a, 'b> {
359         self.inner.entry(entry);
360         self
361     }
362
363     /// Adds the contents of an iterator of entries to the set output.
364     #[stable(feature = "debug_builders", since = "1.2.0")]
365     pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
366         where D: fmt::Debug,
367               I: IntoIterator<Item = D>
368     {
369         for entry in entries {
370             self.entry(&entry);
371         }
372         self
373     }
374
375     /// Finishes output and returns any error encountered.
376     #[stable(feature = "debug_builders", since = "1.2.0")]
377     pub fn finish(&mut self) -> fmt::Result {
378         self.inner.finish();
379         self.inner.result.and_then(|_| self.inner.fmt.write_str("}"))
380     }
381 }
382
383 /// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
384 ///
385 /// This is useful when you wish to output a formatted list of items as a part
386 /// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
387 ///
388 /// This can be constructed by the
389 /// [`Formatter::debug_list`](struct.Formatter.html#method.debug_list)
390 /// method.
391 ///
392 /// # Examples
393 ///
394 /// ```
395 /// use std::fmt;
396 ///
397 /// struct Foo(Vec<i32>);
398 ///
399 /// impl fmt::Debug for Foo {
400 ///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
401 ///         fmt.debug_list().entries(self.0.iter()).finish()
402 ///     }
403 /// }
404 ///
405 /// // prints "[10, 11]"
406 /// println!("{:?}", Foo(vec![10, 11]));
407 /// ```
408 #[must_use]
409 #[allow(missing_debug_implementations)]
410 #[stable(feature = "debug_builders", since = "1.2.0")]
411 pub struct DebugList<'a, 'b: 'a> {
412     inner: DebugInner<'a, 'b>,
413 }
414
415 pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> {
416     let result = write!(fmt, "[");
417     DebugList {
418         inner: DebugInner {
419             fmt,
420             result,
421             has_fields: false,
422         },
423     }
424 }
425
426 impl<'a, 'b: 'a> DebugList<'a, 'b> {
427     /// Adds a new entry to the list output.
428     #[stable(feature = "debug_builders", since = "1.2.0")]
429     pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugList<'a, 'b> {
430         self.inner.entry(entry);
431         self
432     }
433
434     /// Adds the contents of an iterator of entries to the list output.
435     #[stable(feature = "debug_builders", since = "1.2.0")]
436     pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
437         where D: fmt::Debug,
438               I: IntoIterator<Item = D>
439     {
440         for entry in entries {
441             self.entry(&entry);
442         }
443         self
444     }
445
446     /// Finishes output and returns any error encountered.
447     #[stable(feature = "debug_builders", since = "1.2.0")]
448     pub fn finish(&mut self) -> fmt::Result {
449         self.inner.finish();
450         self.inner.result.and_then(|_| self.inner.fmt.write_str("]"))
451     }
452 }
453
454 /// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
455 ///
456 /// This is useful when you wish to output a formatted map as a part of your
457 /// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
458 ///
459 /// This can be constructed by the
460 /// [`Formatter::debug_map`](struct.Formatter.html#method.debug_map)
461 /// method.
462 ///
463 /// # Examples
464 ///
465 /// ```
466 /// use std::fmt;
467 ///
468 /// struct Foo(Vec<(String, i32)>);
469 ///
470 /// impl fmt::Debug for Foo {
471 ///     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
472 ///         fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
473 ///     }
474 /// }
475 ///
476 /// // prints "{"A": 10, "B": 11}"
477 /// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)]));
478 /// ```
479 #[must_use]
480 #[allow(missing_debug_implementations)]
481 #[stable(feature = "debug_builders", since = "1.2.0")]
482 pub struct DebugMap<'a, 'b: 'a> {
483     fmt: &'a mut fmt::Formatter<'b>,
484     result: fmt::Result,
485     has_fields: bool,
486 }
487
488 pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
489     let result = write!(fmt, "{{");
490     DebugMap {
491         fmt,
492         result,
493         has_fields: false,
494     }
495 }
496
497 impl<'a, 'b: 'a> DebugMap<'a, 'b> {
498     /// Adds a new entry to the map output.
499     #[stable(feature = "debug_builders", since = "1.2.0")]
500     pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> {
501         self.result = self.result.and_then(|_| {
502             if self.is_pretty() {
503                 use fmt::Write;
504                 let mut writer = PadAdapter::new(self.fmt);
505                 writer.write_str(if self.has_fields {
506                     ",\n"
507                 } else {
508                     "\n"
509                 })?;
510                 key.fmt(&mut writer.as_formatter())?;
511                 writer.write_str(": ")?;
512                 value.fmt(&mut writer.as_formatter())
513             } else {
514                 if self.has_fields {
515                     self.fmt.write_str(", ")?
516                 }
517                 key.fmt(self.fmt)?;
518                 self.fmt.write_str(": ")?;
519                 value.fmt(self.fmt)
520             }
521         });
522
523         self.has_fields = true;
524         self
525     }
526
527     /// Adds the contents of an iterator of entries to the map output.
528     #[stable(feature = "debug_builders", since = "1.2.0")]
529     pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
530         where K: fmt::Debug,
531               V: fmt::Debug,
532               I: IntoIterator<Item = (K, V)>
533     {
534         for (k, v) in entries {
535             self.entry(&k, &v);
536         }
537         self
538     }
539
540     /// Finishes output and returns any error encountered.
541     #[stable(feature = "debug_builders", since = "1.2.0")]
542     pub fn finish(&mut self) -> fmt::Result {
543         let prefix = if self.is_pretty() && self.has_fields {
544             "\n"
545         } else {
546             ""
547         };
548         self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
549     }
550
551     fn is_pretty(&self) -> bool {
552         self.fmt.alternate()
553     }
554 }