1#[macro_export]
46macro_rules! forward_display {
47 (<$($generic:ident),+> in $this:ty => $field:ident) => {
48 impl <$($generic: ::core::fmt::Display),+> ::core::fmt::Display for $this {
49 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
50 ::core::fmt::Display::fmt(&self.$field, fmt)
51 }
52 }
53 };
54
55 (<$($generic:ident),+> in $this:ty) => {
56 impl <$($generic: ::core::fmt::Display),+> ::core::fmt::Display for $this {
57 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
58 ::core::fmt::Display::fmt(&self.0, fmt)
59 }
60 }
61 };
62
63 ($ty:ty) => {
64 impl ::core::fmt::Display for $ty {
65 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
66 ::core::fmt::Display::fmt(&self.0, fmt)
67 }
68 }
69 };
70
71 ($ty:ty => $field:ident) => {
72 impl ::core::fmt::Display for $ty {
73 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
74 ::core::fmt::Display::fmt(&self.$field, fmt)
75 }
76 }
77 };
78}
79
80#[macro_export]
110macro_rules! impl_display {
111 ($ty:ty; $format:literal) => {
113 impl ::core::fmt::Display for $ty {
114 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
115 ::core::write!(fmt, $format)
116 }
117 }
118 };
119
120 ($ty:ty; $format:literal, $($args:expr),+) => {
122 impl ::core::fmt::Display for $ty {
123 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
124 ::core::write!(fmt, $format, $($args),+)
125 }
126 }
127 };
128
129 ($ty:ty; $format:literal, $($args:expr),+ ,) => {
131 $crate::impl_display!($ty; $format, $($args),+);
132 };
133}
134
135#[macro_export]
166macro_rules! impl_display_enum {
167 ($ty:ty, $($variant:ident => $stringified:literal),+) => {
168 impl ::core::fmt::Display for $ty {
169 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
170 fmt.write_str(match self {
171 $(
172 Self::$variant => $stringified,
173 )*
174 })
175 }
176 }
177 };
178
179 ($ty:ty, $($variant:ident => $stringified:literal),+ ,) => {
180 $crate::impl_display_enum!($ty, $($variant => $stringified),+);
181 };
182
183 ($ty:ty, $($variant:ident ($($inner:ident),+) => $format:literal),+) => {
184 impl ::core::fmt::Display for $ty {
185 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
186 use ::core::fmt::Write as _;
187
188 let mut buf = ::std::string::String::new();
191
192 match self {
193 $(
194 Self::$variant($($inner),+) =>
195 ::core::write!(&mut buf, $format, $($inner = $inner),+)?,
196 )*
197 };
198
199 fmt.write_str(&buf)
200 }
201 }
202 };
203
204 ($ty:ty, $($variant:ident ($($inner:ident),+) => $format:literal),+ ,) => {
205 $crate::impl_display_enum!($ty, $($variant ($($inner),+) => $format),+);
206 };
207
208 ($ty:ty, $($variant:ident { $($inner:ident),+ } => $format:literal),+) => {
209 impl ::core::fmt::Display for $ty {
210 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
211 use ::core::fmt::Write as _;
212
213 let mut buf = ::std::string::String::new();
216
217 match self {
218 $(
219 Self::$variant { $($inner),+ } =>
220 ::core::write!(&mut buf, $format, $($inner = $inner),+)?,
221 )*
222 };
223
224 fmt.write_str(&buf)
225 }
226 }
227 };
228
229 ($ty:ty, $($variant:ident { $($inner:ident),+ } => $format:literal),+ ,) => {
230 $crate::impl_display_enum!($ty, $($variant ($($inner),+) => $format),+);
231 };
232
233 }
235
236#[cfg(test)]
237mod tests {
238 use alloc::{
239 borrow::ToOwned as _,
240 string::{String, ToString as _},
241 };
242
243 #[test]
244 fn impl_forward_for_newtype_struct() {
245 struct Foo(String);
246
247 forward_display!(Foo);
248
249 assert_eq!(Foo("hello world".to_owned()).to_string(), "hello world");
250 }
251
252 #[test]
253 fn impl_forward_newtype_named_struct() {
254 struct Foo {
255 inner: u64,
256 }
257
258 forward_display!(Foo => inner);
259
260 assert_eq!(Foo { inner: 42 }.to_string(), "42");
261 }
262
263 #[test]
264 fn impl_forward_generic_newtype_struct() {
265 struct Foo<T>(T);
266
267 forward_display!(<T> in Foo<T>);
268
269 assert_eq!(Foo(42).to_string(), "42");
270 }
271
272 #[test]
273 fn impl_forward_generic_named_struct() {
274 struct Foo<T> {
275 inner: T,
276 }
277
278 forward_display!(<T> in Foo<T> => inner);
279
280 assert_eq!(Foo { inner: 42 }.to_string(), "42");
281 }
282
283 #[test]
284 fn impl_basic_for_unit_struct() {
285 struct Foo;
286 impl_display!(Foo; "foo");
287 assert_eq!(Foo.to_string(), "foo");
288 }
289
290 #[test]
291 fn impl_basic_with_args() {
292 struct Foo;
293 impl_display!(Foo; "foo {} {}", 2, 3);
294 assert_eq!(Foo.to_string(), "foo 2 3");
295 }
296
297 #[rustversion::stable(1.58)]
298 #[test]
299 fn impl_basic_with_inline_args() {
300 const HI: &str = "hello";
301
302 struct Hello3;
303 impl_display!(Hello3; "{HI} world");
304 assert_eq!(Hello3.to_string(), "hello world");
305 }
306}