190 lines
5.4 KiB
Rust
190 lines
5.4 KiB
Rust
//! [`core::fmt::DebugTuple`] reimplementation with
|
|
//! [`DebugTuple::finish_non_exhaustive()`] method.
|
|
|
|
use ::core;
|
|
use core::fmt::{Debug, Formatter, Result, Write};
|
|
use core::prelude::v1::*;
|
|
|
|
/// Same as [`core::fmt::DebugTuple`], but with
|
|
/// [`DebugTuple::finish_non_exhaustive()`] method.
|
|
#[must_use = "must eventually call `finish()` or `finish_non_exhaustive()` on \
|
|
Debug builders"]
|
|
pub struct DebugTuple<'a, 'b: 'a> {
|
|
fmt: &'a mut Formatter<'b>,
|
|
result: Result,
|
|
fields: usize,
|
|
empty_name: bool,
|
|
}
|
|
|
|
/// Creates a new [`DebugTuple`].
|
|
pub fn debug_tuple<'a, 'b>(
|
|
fmt: &'a mut Formatter<'b>,
|
|
name: &str,
|
|
) -> DebugTuple<'a, 'b> {
|
|
let result = fmt.write_str(name);
|
|
DebugTuple {
|
|
fmt,
|
|
result,
|
|
fields: 0,
|
|
empty_name: name.is_empty(),
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
|
|
/// Adds a new field to the generated tuple struct output.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// use core::fmt;
|
|
/// use derive_more::__private::debug_tuple;
|
|
///
|
|
/// struct Foo(i32, String);
|
|
///
|
|
/// impl fmt::Debug for Foo {
|
|
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
/// debug_tuple(fmt, "Foo")
|
|
/// .field(&self.0) // We add the first field.
|
|
/// .field(&self.1) // We add the second field.
|
|
/// .finish() // We're good to go!
|
|
/// }
|
|
/// }
|
|
///
|
|
/// assert_eq!(
|
|
/// format!("{:?}", Foo(10, "Hello World".to_string())),
|
|
/// "Foo(10, \"Hello World\")",
|
|
/// );
|
|
/// ```
|
|
pub fn field(&mut self, value: &dyn Debug) -> &mut Self {
|
|
self.result = self.result.and_then(|_| {
|
|
if self.is_pretty() {
|
|
if self.fields == 0 {
|
|
self.fmt.write_str("(\n")?;
|
|
}
|
|
|
|
let mut padded_formatter = Padded::new(self.fmt);
|
|
padded_formatter.write_fmt(format_args!("{value:#?}"))?;
|
|
padded_formatter.write_str(",\n")
|
|
} else {
|
|
let prefix = if self.fields == 0 { "(" } else { ", " };
|
|
self.fmt.write_str(prefix)?;
|
|
value.fmt(self.fmt)
|
|
}
|
|
});
|
|
|
|
self.fields += 1;
|
|
self
|
|
}
|
|
|
|
/// Finishes output and returns any error encountered.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// use core::fmt;
|
|
/// use derive_more::__private::debug_tuple;
|
|
///
|
|
/// struct Foo(i32, String);
|
|
///
|
|
/// impl fmt::Debug for Foo {
|
|
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
/// debug_tuple(fmt, "Foo")
|
|
/// .field(&self.0)
|
|
/// .field(&self.1)
|
|
/// .finish() // You need to call it to "finish" the
|
|
/// // tuple formatting.
|
|
/// }
|
|
/// }
|
|
///
|
|
/// assert_eq!(
|
|
/// format!("{:?}", Foo(10, "Hello World".to_string())),
|
|
/// "Foo(10, \"Hello World\")",
|
|
/// );
|
|
/// ```
|
|
pub fn finish(&mut self) -> Result {
|
|
if self.fields > 0 {
|
|
self.result = self.result.and_then(|_| {
|
|
if self.fields == 1 && self.empty_name && !self.is_pretty() {
|
|
self.fmt.write_str(",")?;
|
|
}
|
|
self.fmt.write_str(")")
|
|
});
|
|
}
|
|
self.result
|
|
}
|
|
|
|
/// Marks the struct as non-exhaustive, indicating to the reader that there are some other
|
|
/// fields that are not shown in the debug representation, and finishes output, returning any
|
|
/// error encountered.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```rust
|
|
/// use core::fmt;
|
|
/// use derive_more::__private::debug_tuple;
|
|
///
|
|
/// struct Bar(i32, f32);
|
|
///
|
|
/// impl fmt::Debug for Bar {
|
|
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
/// debug_tuple(fmt, "Bar")
|
|
/// .field(&self.0)
|
|
/// .finish_non_exhaustive() // Show that some other field(s) exist.
|
|
/// }
|
|
/// }
|
|
///
|
|
/// assert_eq!(format!("{:?}", Bar(10, 1.0)), "Bar(10, ..)");
|
|
/// ```
|
|
pub fn finish_non_exhaustive(&mut self) -> Result {
|
|
self.result = self.result.and_then(|_| {
|
|
if self.fields > 0 {
|
|
if self.is_pretty() {
|
|
let mut padded_formatter = Padded::new(self.fmt);
|
|
padded_formatter.write_str("..\n")?;
|
|
self.fmt.write_str(")")
|
|
} else {
|
|
self.fmt.write_str(", ..)")
|
|
}
|
|
} else {
|
|
self.fmt.write_str("(..)")
|
|
}
|
|
});
|
|
self.result
|
|
}
|
|
|
|
fn is_pretty(&self) -> bool {
|
|
self.fmt.alternate()
|
|
}
|
|
}
|
|
|
|
/// Wrapper for a [`Formatter`] adding 4 spaces on newlines for inner pretty
|
|
/// printed [`Debug`] values.
|
|
struct Padded<'a, 'b> {
|
|
formatter: &'a mut Formatter<'b>,
|
|
on_newline: bool,
|
|
}
|
|
|
|
impl<'a, 'b> Padded<'a, 'b> {
|
|
fn new(formatter: &'a mut Formatter<'b>) -> Self {
|
|
Self {
|
|
formatter,
|
|
on_newline: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b> Write for Padded<'a, 'b> {
|
|
fn write_str(&mut self, s: &str) -> Result {
|
|
for s in s.split_inclusive('\n') {
|
|
if self.on_newline {
|
|
self.formatter.write_str(" ")?;
|
|
}
|
|
|
|
self.on_newline = s.ends_with('\n');
|
|
self.formatter.write_str(s)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|