derive_more/fmt.rs
1//! [`core::fmt::DebugTuple`] reimplementation with
2//! [`DebugTuple::finish_non_exhaustive()`] method.
3
4use ::core;
5use core::fmt::{Debug, Formatter, Result, Write};
6use core::prelude::v1::*;
7
8/// Same as [`core::fmt::DebugTuple`], but with
9/// [`DebugTuple::finish_non_exhaustive()`] method.
10#[must_use = "must eventually call `finish()` or `finish_non_exhaustive()` on \
11 Debug builders"]
12pub struct DebugTuple<'a, 'b: 'a> {
13 fmt: &'a mut Formatter<'b>,
14 result: Result,
15 fields: usize,
16 empty_name: bool,
17}
18
19/// Creates a new [`DebugTuple`].
20pub fn debug_tuple<'a, 'b>(
21 fmt: &'a mut Formatter<'b>,
22 name: &str,
23) -> DebugTuple<'a, 'b> {
24 let result = fmt.write_str(name);
25 DebugTuple {
26 fmt,
27 result,
28 fields: 0,
29 empty_name: name.is_empty(),
30 }
31}
32
33impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
34 /// Adds a new field to the generated tuple struct output.
35 ///
36 /// # Example
37 ///
38 /// ```rust
39 /// use core::fmt;
40 /// use derive_more::__private::debug_tuple;
41 ///
42 /// struct Foo(i32, String);
43 ///
44 /// impl fmt::Debug for Foo {
45 /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
46 /// debug_tuple(fmt, "Foo")
47 /// .field(&self.0) // We add the first field.
48 /// .field(&self.1) // We add the second field.
49 /// .finish() // We're good to go!
50 /// }
51 /// }
52 ///
53 /// assert_eq!(
54 /// format!("{:?}", Foo(10, "Hello World".to_string())),
55 /// "Foo(10, \"Hello World\")",
56 /// );
57 /// ```
58 pub fn field(&mut self, value: &dyn Debug) -> &mut Self {
59 self.result = self.result.and_then(|_| {
60 if self.is_pretty() {
61 if self.fields == 0 {
62 self.fmt.write_str("(\n")?;
63 }
64
65 let mut padded_formatter = Padded::new(self.fmt);
66 padded_formatter.write_fmt(format_args!("{value:#?}"))?;
67 padded_formatter.write_str(",\n")
68 } else {
69 let prefix = if self.fields == 0 { "(" } else { ", " };
70 self.fmt.write_str(prefix)?;
71 value.fmt(self.fmt)
72 }
73 });
74
75 self.fields += 1;
76 self
77 }
78
79 /// Finishes output and returns any error encountered.
80 ///
81 /// # Example
82 ///
83 /// ```
84 /// use core::fmt;
85 /// use derive_more::__private::debug_tuple;
86 ///
87 /// struct Foo(i32, String);
88 ///
89 /// impl fmt::Debug for Foo {
90 /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
91 /// debug_tuple(fmt, "Foo")
92 /// .field(&self.0)
93 /// .field(&self.1)
94 /// .finish() // You need to call it to "finish" the
95 /// // tuple formatting.
96 /// }
97 /// }
98 ///
99 /// assert_eq!(
100 /// format!("{:?}", Foo(10, "Hello World".to_string())),
101 /// "Foo(10, \"Hello World\")",
102 /// );
103 /// ```
104 pub fn finish(&mut self) -> Result {
105 if self.fields > 0 {
106 self.result = self.result.and_then(|_| {
107 if self.fields == 1 && self.empty_name && !self.is_pretty() {
108 self.fmt.write_str(",")?;
109 }
110 self.fmt.write_str(")")
111 });
112 }
113 self.result
114 }
115
116 /// Marks the struct as non-exhaustive, indicating to the reader that there are some other
117 /// fields that are not shown in the debug representation, and finishes output, returning any
118 /// error encountered.
119 ///
120 /// # Example
121 ///
122 /// ```rust
123 /// use core::fmt;
124 /// use derive_more::__private::debug_tuple;
125 ///
126 /// struct Bar(i32, f32);
127 ///
128 /// impl fmt::Debug for Bar {
129 /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
130 /// debug_tuple(fmt, "Bar")
131 /// .field(&self.0)
132 /// .finish_non_exhaustive() // Show that some other field(s) exist.
133 /// }
134 /// }
135 ///
136 /// assert_eq!(format!("{:?}", Bar(10, 1.0)), "Bar(10, ..)");
137 /// ```
138 pub fn finish_non_exhaustive(&mut self) -> Result {
139 self.result = self.result.and_then(|_| {
140 if self.fields > 0 {
141 if self.is_pretty() {
142 let mut padded_formatter = Padded::new(self.fmt);
143 padded_formatter.write_str("..\n")?;
144 self.fmt.write_str(")")
145 } else {
146 self.fmt.write_str(", ..)")
147 }
148 } else {
149 self.fmt.write_str("(..)")
150 }
151 });
152 self.result
153 }
154
155 fn is_pretty(&self) -> bool {
156 self.fmt.alternate()
157 }
158}
159
160/// Wrapper for a [`Formatter`] adding 4 spaces on newlines for inner pretty
161/// printed [`Debug`] values.
162struct Padded<'a, 'b> {
163 formatter: &'a mut Formatter<'b>,
164 on_newline: bool,
165}
166
167impl<'a, 'b> Padded<'a, 'b> {
168 fn new(formatter: &'a mut Formatter<'b>) -> Self {
169 Self {
170 formatter,
171 on_newline: true,
172 }
173 }
174}
175
176impl Write for Padded<'_, '_> {
177 fn write_str(&mut self, s: &str) -> Result {
178 for s in s.split_inclusive('\n') {
179 if self.on_newline {
180 self.formatter.write_str(" ")?;
181 }
182
183 self.on_newline = s.ends_with('\n');
184 self.formatter.write_str(s)?;
185 }
186
187 Ok(())
188 }
189}