#[macro_export]
macro_rules! forward_display {
(<$($generic:ident),+> in $this:ty => $field:ident) => {
impl <$($generic: ::core::fmt::Display),+> ::core::fmt::Display for $this {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Display::fmt(&self.$field, fmt)
}
}
};
(<$($generic:ident),+> in $this:ty) => {
impl <$($generic: ::core::fmt::Display),+> ::core::fmt::Display for $this {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Display::fmt(&self.0, fmt)
}
}
};
($ty:ty) => {
impl ::core::fmt::Display for $ty {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Display::fmt(&self.0, fmt)
}
}
};
($ty:ty => $field:ident) => {
impl ::core::fmt::Display for $ty {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Display::fmt(&self.$field, fmt)
}
}
};
}
#[macro_export]
macro_rules! impl_display {
($ty:ty; $format:literal) => {
impl ::core::fmt::Display for $ty {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::write!(fmt, $format)
}
}
};
($ty:ty; $format:literal, $($args:expr),+) => {
impl ::core::fmt::Display for $ty {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::write!(fmt, $format, $($args),+)
}
}
};
($ty:ty; $format:literal, $($args:expr),+ ,) => {
$crate::impl_display!($ty; $format, $($args),+);
};
}
#[macro_export]
macro_rules! impl_display_enum {
($ty:ty, $($variant:ident => $stringified:literal),+) => {
impl ::core::fmt::Display for $ty {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
fmt.write_str(match self {
$(
Self::$variant => $stringified,
)*
})
}
}
};
($ty:ty, $($variant:ident => $stringified:literal),+ ,) => {
$crate::impl_display_enum!($ty, $($variant => $stringified),+);
};
($ty:ty, $($variant:ident ($($inner:ident),+) => $format:literal),+) => {
impl ::core::fmt::Display for $ty {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
use ::core::fmt::Write as _;
let mut buf = ::std::string::String::new();
match self {
$(
Self::$variant($($inner),+) =>
::core::write!(&mut buf, $format, $($inner = $inner),+)?,
)*
};
fmt.write_str(&buf)
}
}
};
($ty:ty, $($variant:ident ($($inner:ident),+) => $format:literal),+ ,) => {
$crate::impl_display_enum!($ty, $($variant ($($inner),+) => $format),+);
};
($ty:ty, $($variant:ident { $($inner:ident),+ } => $format:literal),+) => {
impl ::core::fmt::Display for $ty {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
use ::core::fmt::Write as _;
let mut buf = ::std::string::String::new();
match self {
$(
Self::$variant { $($inner),+ } =>
::core::write!(&mut buf, $format, $($inner = $inner),+)?,
)*
};
fmt.write_str(&buf)
}
}
};
($ty:ty, $($variant:ident { $($inner:ident),+ } => $format:literal),+ ,) => {
$crate::impl_display_enum!($ty, $($variant ($($inner),+) => $format),+);
};
}
#[cfg(test)]
mod tests {
use alloc::{
borrow::ToOwned as _,
string::{String, ToString as _},
};
#[test]
fn impl_forward_for_newtype_struct() {
struct Foo(String);
forward_display!(Foo);
assert_eq!(Foo("hello world".to_owned()).to_string(), "hello world");
}
#[test]
fn impl_forward_newtype_named_struct() {
struct Foo {
inner: u64,
}
forward_display!(Foo => inner);
assert_eq!(Foo { inner: 42 }.to_string(), "42");
}
#[test]
fn impl_forward_generic_newtype_struct() {
struct Foo<T>(T);
forward_display!(<T> in Foo<T>);
assert_eq!(Foo(42).to_string(), "42");
}
#[test]
fn impl_forward_generic_named_struct() {
struct Foo<T> {
inner: T,
}
forward_display!(<T> in Foo<T> => inner);
assert_eq!(Foo { inner: 42 }.to_string(), "42");
}
#[test]
fn impl_basic_for_unit_struct() {
struct Foo;
impl_display!(Foo; "foo");
assert_eq!(Foo.to_string(), "foo");
}
#[test]
fn impl_basic_with_args() {
struct Foo;
impl_display!(Foo; "foo {} {}", 2, 3);
assert_eq!(Foo.to_string(), "foo 2 3");
}
#[rustversion::stable(1.58)]
#[test]
fn impl_basic_with_inline_args() {
const HI: &str = "hello";
struct Hello3;
impl_display!(Hello3; "{HI} world");
assert_eq!(Hello3.to_string(), "hello world");
}
}