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}