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
291use alloc::fmt::{Debug, Formatter, Result as FormatResult};
292use alloc::string::String;
293
294#[doc(hidden)]
295pub struct RawString(pub String);
296
297impl Debug for RawString {
298    fn fmt(&self, f: &mut Formatter<'_>) -> FormatResult {
299        if f.alternate() {
300            f.write_str(self.0.replace('\n', "\n    ").as_str())
301        } else {
302            f.write_str(self.0.as_str())
303        }
304    }
305}
306
307#[macro_export]
308macro_rules! impl_debug_for_struct {
309    // TODO unit struct
310    ($struct_name:ident, $formatter:expr $(, $self:expr)? $(,)*) => {
311        return $formatter.write_str(stringify!($struct_name));
312    };
313    // TODO struct
314    ($struct_name:ident, $formatter:expr, $self:expr, $( $(.$field:ident)? $((.$field_2:ident, $($field_2_fmt:tt)+))? $(let .$field_3:ident = $field_3_value:expr)? ),* $(,)*) => {
315        {
316            let mut builder = $formatter.debug_struct(stringify!($struct_name));
317
318            $(
319                $(
320                    builder.field(stringify!($field), &$self.$field);
321                )?
322
323                $(
324                    builder.field(stringify!($field_2), &$crate::RawString(format!($($field_2_fmt)*)));
325                )?
326
327                $(
328                    builder.field(stringify!($field_3), &$field_3_value);
329                )?
330            )*
331
332            return builder.finish();
333        }
334    };
335}
336
337#[macro_export]
338macro_rules! impl_debug_for_tuple_struct {
339    // TODO unit tuple struct
340    ($struct_name:ident, $formatter:expr $(, $self:expr)? $(,)*) => {
341        return $formatter.write_str(stringify!($struct_name));
342    };
343    // TODO tuple struct
344    ($struct_name:ident, $formatter:expr, $self:expr, $( $(.$field:tt)? $((.$field_2:tt, $($field_2_fmt:tt)+))? $(let .$field_3:tt = $field_3_value:expr)? ),* $(,)*) => {
345        {
346            let mut builder = $formatter.debug_tuple(stringify!($struct_name));
347
348            $(
349                $(
350                    builder.field(&$self.$field);
351                )?
352
353                $(
354                    builder.field(&$crate::RawString(format!($($field_2_fmt)*)));
355                )?
356
357                $(
358                    builder.field(&$field_3_value);
359                )?
360            )*
361
362            return builder.finish();
363        }
364    }
365}
366
367#[macro_export]
368macro_rules! impl_debug_for_enum {
369    // TODO enum
370    ($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 $(,)*) => {
371        {
372            match $self {
373                $(
374                    $(
375                        Self::$variant_unit => {
376                            return $formatter.write_str(stringify!($variant_unit));
377                        }
378                    )?
379                    $(
380                        Self::$variant_tuple ($($tuple)*)=> {
381                            let mut builder = $formatter.debug_tuple(stringify!($variant_tuple));
382
383                            $(
384                                $(
385                                    $(
386                                        builder.field(&$t_field);
387                                    )?
388
389                                    $(
390                                        builder.field(&$crate::RawString(format!($($t_field_2_fmt)*)));
391                                    )?
392
393                                    $(
394                                        builder.field(&$t_field_3_value);
395                                    )?
396                                )*
397                            )?
398
399                            return builder.finish();
400                        }
401                    )?
402                    $(
403                        Self::$variant_struct {$($struct)*}=> {
404                            let mut builder = $formatter.debug_struct(stringify!($variant_struct));
405
406                            $(
407                                $(
408                                    $(
409                                        builder.field(stringify!($s_field), &$s_field);
410                                    )?
411
412                                    $(
413                                        builder.field(stringify!($s_field_2), &$crate::RawString(format!($($s_field_2_fmt)*)));
414                                    )?
415
416                                    $(
417                                        builder.field(stringify!($s_field_3), &$s_field_3_value);
418                                    )?
419                                )*
420                            )?
421
422                            return builder.finish();
423                        }
424                    )?
425                )+
426            }
427        }
428    };
429    // TODO enum full path
430    ({$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 $(,)*) => {
431        {
432            match $self {
433                $(
434                    $(
435                        Self::$variant_unit => {
436                            $formatter.write_str(stringify!($enum_name))?;
437                            $formatter.write_str("::")?;
438                            return $formatter.write_str(stringify!($variant_unit));
439                        }
440                    )?
441                    $(
442                        Self::$variant_tuple ($($tuple)*)=> {
443                            let mut builder = $formatter.debug_tuple(&format!("{}::{}", stringify!($enum_name), stringify!($variant_tuple)));
444
445                            $(
446                                $(
447                                    $(
448                                        builder.field(&$t_field);
449                                    )?
450
451                                    $(
452                                        builder.field(&$crate::RawString(format!($($t_field_2_fmt)*)));
453                                    )?
454
455                                    $(
456                                        builder.field(&$t_field_3_value);
457                                    )?
458                                )*
459                            )?
460
461                            return builder.finish();
462                        }
463                    )?
464                    $(
465                        Self::$variant_struct {$($struct)*}=> {
466                            let mut builder = $formatter.debug_struct(&format!("{}::{}", stringify!($enum_name), stringify!($variant_struct)));
467
468                            $(
469                                $(
470                                    $(
471                                        builder.field(stringify!($s_field), &$s_field);
472                                    )?
473
474                                    $(
475                                        builder.field(stringify!($s_field_2), &$crate::RawString(format!($($s_field_2_fmt)*)));
476                                    )?
477
478                                    $(
479                                        builder.field(stringify!($s_field_3), &$s_field_3_value);
480                                    )?
481                                )*
482                            )?
483
484                            return builder.finish();
485                        }
486                    )?
487                )+
488            }
489        }
490    };
491}