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:tt),+) => $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($($crate::impl_display_enum!(iou @ $inner)),+) =>
195 ::core::write!(&mut buf, $format)?,
196 )*
197 };
198
199 fmt.write_str(&buf)
200 }
201 }
202 };
203
204 ($ty:ty: $($variant:ident ($($inner:tt),+) => $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)?,
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 (iou @ $ident:ident) => {
234 $ident
235 };
236
237 (iou @ $ident:ident) => {
239 $ident
240 };
241
242 (iou @ _) => {
244 _
245 };
246
247
248 }
250
251#[cfg(test)]
252mod tests {
253 use alloc::{
254 borrow::ToOwned as _,
255 string::{String, ToString as _},
256 };
257
258 #[test]
259 fn impl_forward_for_newtype_struct() {
260 struct Foo(String);
261
262 forward_display!(Foo);
263
264 assert_eq!(Foo("hello world".to_owned()).to_string(), "hello world");
265 }
266
267 #[test]
268 fn impl_forward_newtype_named_struct() {
269 struct Foo {
270 inner: u64,
271 }
272
273 forward_display!(Foo => inner);
274
275 assert_eq!(Foo { inner: 42 }.to_string(), "42");
276 }
277
278 #[test]
279 fn impl_forward_generic_newtype_struct() {
280 struct Foo<T>(T);
281
282 forward_display!(<T> in Foo<T>);
283
284 assert_eq!(Foo(42).to_string(), "42");
285 }
286
287 #[test]
288 fn impl_forward_generic_named_struct() {
289 struct Foo<T> {
290 inner: T,
291 }
292
293 forward_display!(<T> in Foo<T> => inner);
294
295 assert_eq!(Foo { inner: 42 }.to_string(), "42");
296 }
297
298 #[test]
299 fn impl_basic_for_unit_struct() {
300 struct Foo;
301 impl_display!(Foo: "foo");
302 assert_eq!(Foo.to_string(), "foo");
303 }
304
305 #[test]
306 fn impl_basic_with_args() {
307 struct Foo;
308 impl_display!(Foo: "foo {} {}", 2, 3);
309 assert_eq!(Foo.to_string(), "foo 2 3");
310 }
311
312 #[test]
313 fn impl_basic_with_inline_args() {
314 const HI: &str = "hello";
315
316 struct Hello3;
317 impl_display!(Hello3: "{HI} world");
318 assert_eq!(Hello3.to_string(), "hello world");
319 }
320}