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