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}