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