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}