Skip to main content

debug_helper/
lib.rs

1/*!
2# Debug Helper
3
4This crate provides declarative macros to help you implement the `Debug` trait manually.
5
6Instead of this crate, in most cases, you can use the [`educe`](https://crates.io/crates/educe) crate to implement the `Debug` trait.
7
8## Examples
9
10For structs,
11
12```rust
13use std::fmt::{self, Formatter, Debug};
14
15pub struct A {
16    pub f1: u8,
17    pub f2: i16,
18    pub f3: f64,
19}
20
21impl Debug for A {
22    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
23        debug_helper::impl_debug_for_struct!(A, f, self, .f1, (.f3, "{:.3}", self.f3));
24    }
25}
26
27let a = A {
28    f1: 1,
29    f2: 2,
30    f3: std::f64::consts::PI,
31};
32
33println!("{:#?}", a);
34
35/*
36    A {
37        f1: 1,
38        f3: 3.142,
39    }
40*/
41```
42
43For tuple structs,
44
45```rust
46use std::fmt::{self, Formatter, Debug};
47
48pub struct A(pub u8, pub i16, pub f64);
49
50impl Debug for A {
51    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
52        debug_helper::impl_debug_for_tuple_struct!(A, f, self, .0, (.2, "{:.3}", self.2));
53    }
54}
55
56let a = A(1, 2, std::f64::consts::PI);
57
58println!("{:#?}", a);
59
60/*
61    A(
62        1,
63        3.142,
64    )
65*/
66```
67
68For enums (without the enum name),
69
70```rust
71use std::fmt::{self, Formatter, Debug};
72
73pub enum A {
74    V1,
75    V2(u8, i16, f64),
76    V3 {
77        f1: u8,
78        f2: i16,
79        f3: f64,
80    },
81}
82
83impl Debug for A {
84    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
85        debug_helper::impl_debug_for_enum!(A::{V1, (V2(f1, _, f3): (.f1, (.f3, "{:.3}", f3))), {V3{f1, f2: _, f3}: (.f1, (.f3, "{:.3}", f3))}}, f, self);
86    }
87}
88
89let a = A::V1;
90let b = A::V2(1, 2, std::f64::consts::PI);
91let c = A::V3{
92    f1: 1,
93    f2: 2,
94    f3: std::f64::consts::PI,
95};
96
97println!("{:#?}", a);
98println!("{:#?}", b);
99println!("{:#?}", c);
100
101/*
102    V1
103    V2(
104        1,
105        3.142,
106    )
107    V3 {
108        f1: 1,
109        f3: 3.142,
110    }
111*/
112```
113
114For enums (with the enum name),
115
116```rust
117use std::fmt::{self, Formatter, Debug};
118
119pub enum A {
120    V1,
121    V2(u8, i16, f64),
122    V3 {
123        f1: u8,
124        f2: i16,
125        f3: f64,
126    },
127}
128
129impl Debug for A {
130    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
131        debug_helper::impl_debug_for_enum!({A::V1, (V2(f1, _, f3): (.f1, (.f3, "{:.3}", f3))), {V3{f1, f2: _, f3}: (.f1, (.f3, "{:.3}", f3))}}, f, self);
132    }
133}
134
135let a = A::V1;
136let b = A::V2(1, 2, std::f64::consts::PI);
137let c = A::V3{
138    f1: 1,
139    f2: 2,
140    f3: std::f64::consts::PI,
141};
142
143println!("{:#?}", a);
144println!("{:#?}", b);
145println!("{:#?}", c);
146
147/*
148    A::V1
149    A::V2(
150        1,
151        3.142,
152    )
153    A::V3 {
154        f1: 1,
155        f3: 3.142,
156    }
157*/
158```
159
160
161
162Ghost fields,
163
164```rust
165use std::fmt::{self, Formatter, Debug};
166
167pub struct A {
168    pub f1: u8,
169    pub f2: i16,
170    pub f3: f64,
171}
172
173impl Debug for A {
174    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
175        debug_helper::impl_debug_for_struct!(A, f, self, .f1, (.f3, "{:.3}", self.f3), (.sum, "{:.3}", self.f1 as f64 + self.f2 as f64 + self.f3));
176    }
177}
178
179let a = A {
180    f1: 1,
181    f2: 2,
182    f3: std::f64::consts::PI,
183};
184
185println!("{:#?}", a);
186
187/*
188    A {
189        f1: 1,
190        f3: 3.142,
191        sum: 6.142,
192    }
193*/
194```
195
196```rust
197use std::fmt::{self, Formatter, Debug};
198
199pub struct A(pub u8, pub i16, pub f64);
200
201impl Debug for A {
202    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
203        debug_helper::impl_debug_for_tuple_struct!(A, f, self, .0, (.2, "{:.3}", self.2), (.3, "{:.3}", self.0 as f64 + self.1 as f64 + self.2));
204    }
205}
206
207let a = A(1, 2, std::f64::consts::PI);
208
209println!("{:#?}", a);
210
211/*
212    A(
213        1,
214        3.142,
215        6.142,
216    )
217*/
218```
219
220Fake structs,
221
222```rust
223use std::fmt::{self, Formatter, Debug};
224
225pub struct A(pub u8, pub i16, pub f64);
226
227impl Debug for A {
228    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
229        debug_helper::impl_debug_for_struct!(A, f, self, let .f1 = self.0, let .f2 = self.1, let .f3 = self.2);
230    }
231}
232
233let a = A(1, 2, std::f64::consts::PI);
234
235println!("{:#?}", a);
236
237/*
238    A {
239        f1: 1,
240        f2: 2,
241        f3: 3.141592653589793,
242    }
243*/
244```
245
246Fake tuple structs,
247
248```rust
249use std::fmt::{self, Formatter, Debug};
250
251pub struct A {
252    pub f1: u8,
253    pub f2: i16,
254    pub f3: f64,
255}
256
257impl Debug for A {
258    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
259        debug_helper::impl_debug_for_tuple_struct!(A, f, self, let .0 = self.f1, let .1 = self.f2, let .2 = self.f3);
260    }
261}
262
263let a = A {
264    f1: 1,
265    f2: 2,
266    f3: std::f64::consts::PI,
267};
268
269println!("{:#?}", a);
270
271/*
272    A(
273        1,
274        2,
275        3.141592653589793,
276    )
277*/
278```
279
280## TODO
281
2821. Fake enum struct variants and tuple variants.
2831. Enum variants can be renamed.
284
285*/
286
287#![no_std]
288
289extern crate alloc;
290
291#[doc(hidden)]
292pub mod __private {
293    pub use alloc::format;
294    use alloc::{
295        fmt::{Debug, Formatter, Result as FormatResult},
296        string::String,
297    };
298
299    pub struct RawString(pub String);
300
301    impl Debug for RawString {
302        fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
303            if f.alternate() {
304                f.write_str(self.0.replace('\n', "\n    ").as_str())
305            } else {
306                f.write_str(self.0.as_str())
307            }
308        }
309    }
310}
311
312#[doc(hidden)]
313pub use __private::RawString;
314
315#[macro_export]
316macro_rules! impl_debug_for_struct {
317    // TODO unit struct
318    ($struct_name:ident, $formatter:expr $(, $self:expr)? $(,)*) => {
319        return $formatter.write_str(stringify!($struct_name));
320    };
321    // TODO struct
322    ($struct_name:ident, $formatter:expr, $self:expr, $( $(.$field:ident)? $((.$field_2:ident, $($field_2_fmt:tt)+))? $(let .$field_3:ident = $field_3_value:expr)? ),* $(,)*) => {
323        {
324            let mut builder = $formatter.debug_struct(stringify!($struct_name));
325
326            $(
327                $(
328                    builder.field(stringify!($field), &$self.$field);
329                )?
330
331                $(
332                    builder.field(stringify!($field_2), &$crate::__private::RawString($crate::__private::format!($($field_2_fmt)*)));
333                )?
334
335                $(
336                    builder.field(stringify!($field_3), &$field_3_value);
337                )?
338            )*
339
340            return builder.finish();
341        }
342    };
343}
344
345#[macro_export]
346macro_rules! impl_debug_for_tuple_struct {
347    // TODO unit tuple struct
348    ($struct_name:ident, $formatter:expr $(, $self:expr)? $(,)*) => {
349        return $formatter.write_str(stringify!($struct_name));
350    };
351    // TODO tuple struct
352    ($struct_name:ident, $formatter:expr, $self:expr, $( $(.$field:tt)? $((.$field_2:tt, $($field_2_fmt:tt)+))? $(let .$field_3:tt = $field_3_value:expr)? ),* $(,)*) => {
353        {
354            let mut builder = $formatter.debug_tuple(stringify!($struct_name));
355
356            $(
357                $(
358                    builder.field(&$self.$field);
359                )?
360
361                $(
362                    builder.field(&$crate::__private::RawString($crate::__private::format!($($field_2_fmt)*)));
363                )?
364
365                $(
366                    builder.field(&$field_3_value);
367                )?
368            )*
369
370            return builder.finish();
371        }
372    }
373}
374
375#[macro_export]
376macro_rules! impl_debug_for_enum {
377    // TODO enum
378    ($enum_name:ident::{$( $($variant_unit:ident)? $(($variant_tuple:ident ($($tuple:tt)*) $(:($( $(.$t_field:tt)? $((.$t_field_2:tt, $($t_field_2_fmt:tt)+))? $(let .$t_field_3:tt = $t_field_3_value:expr)? ),* $(,)*))? ) )? $({$variant_struct:ident {$($struct:tt)*} $(:($( $(.$s_field:tt)? $((.$s_field_2:tt, $($s_field_2_fmt:tt)+))? $(let .$s_field_3:ident = $s_field_3_value:expr)? ),* $(,)*))? })? ),+ $(,)*}, $formatter:expr, $self:expr $(,)*) => {
379        {
380            match $self {
381                $(
382                    $(
383                        Self::$variant_unit => {
384                            return $formatter.write_str(stringify!($variant_unit));
385                        }
386                    )?
387                    $(
388                        Self::$variant_tuple ($($tuple)*)=> {
389                            let mut builder = $formatter.debug_tuple(stringify!($variant_tuple));
390
391                            $(
392                                $(
393                                    $(
394                                        builder.field(&$t_field);
395                                    )?
396
397                                    $(
398                                        builder.field(&$crate::__private::RawString($crate::__private::format!($($t_field_2_fmt)*)));
399                                    )?
400
401                                    $(
402                                        builder.field(&$t_field_3_value);
403                                    )?
404                                )*
405                            )?
406
407                            return builder.finish();
408                        }
409                    )?
410                    $(
411                        Self::$variant_struct {$($struct)*}=> {
412                            let mut builder = $formatter.debug_struct(stringify!($variant_struct));
413
414                            $(
415                                $(
416                                    $(
417                                        builder.field(stringify!($s_field), &$s_field);
418                                    )?
419
420                                    $(
421                                        builder.field(stringify!($s_field_2), &$crate::__private::RawString($crate::__private::format!($($s_field_2_fmt)*)));
422                                    )?
423
424                                    $(
425                                        builder.field(stringify!($s_field_3), &$s_field_3_value);
426                                    )?
427                                )*
428                            )?
429
430                            return builder.finish();
431                        }
432                    )?
433                )+
434            }
435        }
436    };
437    // TODO enum full path
438    ({$enum_name:ident::$( $($variant_unit:ident)? $(($variant_tuple:ident ($($tuple:tt)*) $(:($( $(.$t_field:tt)? $((.$t_field_2:tt, $($t_field_2_fmt:tt)+))? $(let .$t_field_3:tt = $t_field_3_value:expr)? ),* $(,)*))? ) )? $({$variant_struct:ident {$($struct:tt)*} $(:($( $(.$s_field:tt)? $((.$s_field_2:tt, $($s_field_2_fmt:tt)+))? $(let .$s_field_3:ident = $s_field_3_value:expr)? ),* $(,)*))? })? ),+ $(,)*}, $formatter:expr, $self:expr $(,)*) => {
439        {
440            match $self {
441                $(
442                    $(
443                        Self::$variant_unit => {
444                            $formatter.write_str(stringify!($enum_name))?;
445                            $formatter.write_str("::")?;
446                            return $formatter.write_str(stringify!($variant_unit));
447                        }
448                    )?
449                    $(
450                        Self::$variant_tuple ($($tuple)*)=> {
451                            let mut builder = $formatter.debug_tuple(concat!(stringify!($enum_name), "::", stringify!($variant_tuple)));
452
453                            $(
454                                $(
455                                    $(
456                                        builder.field(&$t_field);
457                                    )?
458
459                                    $(
460                                        builder.field(&$crate::__private::RawString($crate::__private::format!($($t_field_2_fmt)*)));
461                                    )?
462
463                                    $(
464                                        builder.field(&$t_field_3_value);
465                                    )?
466                                )*
467                            )?
468
469                            return builder.finish();
470                        }
471                    )?
472                    $(
473                        Self::$variant_struct {$($struct)*}=> {
474                            let mut builder = $formatter.debug_struct(concat!(stringify!($enum_name), "::", stringify!($variant_struct)));
475
476                            $(
477                                $(
478                                    $(
479                                        builder.field(stringify!($s_field), &$s_field);
480                                    )?
481
482                                    $(
483                                        builder.field(stringify!($s_field_2), &$crate::__private::RawString($crate::__private::format!($($s_field_2_fmt)*)));
484                                    )?
485
486                                    $(
487                                        builder.field(stringify!($s_field_3), &$s_field_3_value);
488                                    )?
489                                )*
490                            )?
491
492                            return builder.finish();
493                        }
494                    )?
495                )+
496            }
497        }
498    };
499}