Macro Debug
macro_rules! Debug { ... }
What #[derive(Debug)] generates
This derive macro is a clever superset of Debug from standard library. Additional features include:
- not imposing redundant trait bounds;
#[debug(skip)](or#[debug(ignore)]) attribute to skip formatting struct field or enum variant;#[debug("...", args...)]to specify custom formatting either for the whole struct or enum variant, or its particular field;#[debug(bounds(...))]to impose additional custom trait bounds.
The format of the format
You supply a format by placing an attribute on a struct or enum variant, or its particular field:
#[debug("...", args...)]. The format is exactly like in format!() or any other format_args!()-based macros.
The variables available in the arguments is self and each member of the
struct or enum variant, with members of tuple structs being named with a
leading underscore and their index, i.e. _0, _1, _2, etc. Due to
ownership/lifetime limitations the member variables are all references to the
fields, except when used directly in the format string. For most purposes this
detail doesn't matter, but it is quite important when using Pointer
formatting. If you don't use the {field:p} syntax, you have to dereference
once to get the address of the field itself, instead of the address of the
reference to the field:
use Debug;
let a = &123;
assert_eq!;
Generic data types
When deriving Debug for a generic struct/enum, all generic type arguments used during formatting
are bound by respective formatting trait.
E.g., for a structure Foo defined like this:
use Debug;
")]
a: T1,
#[debug("")]
b: <T2 as Trait>::Type,
#[debug("")]
c: Vec<T3>,
#[debug("")]
d: &'a T1,
#[debug(skip)] // or #[debug(ignore)]
e: T4,
}
trait Trait { type Type; }
The following where clauses would be generated:
T1: Display<T2 as Trait>::Type: DisplayVec<T3>: Debug&'a T1: Pointer
Custom trait bounds
Sometimes you may want to specify additional trait bounds on your generic type parameters, so that they could be used
during formatting. This can be done with a #[debug(bound(...))] attribute.
#[debug(bound(...))] accepts code tokens in a format similar to the format used in angle bracket list (or where
clause predicates): T: MyTrait, U: Trait1 + Trait2.
Using #[debug("...", ...)] formatting we'll try our best to infer trait bounds, but in more advanced cases this isn't
possible. Our aim is to avoid imposing additional bounds, as they can be added with #[debug(bound(...))].
In the example below, we can infer only that V: Display, other bounds have to be supplied by the user:
use Display;
use Debug;
", a.my_function())]
a: T,
#[debug("", b.to_string().len())]
b: U,
#[debug("")]
c: V,
#[debug(skip)] // or #[debug(ignore)]
d: F,
}
trait MyTrait { fn my_function(&self) -> i32; }
Transparency
If the top-level #[debug("...", args...)] attribute (the one for a whole struct or variant) is specified
and can be trivially substituted with a transparent delegation call to the inner type, then all the additional
formatting parameters do work as expected:
use Debug;
// the same as calling `Octal::fmt()`
;
// so, additional formatting parameters do work transparently
assert_eq!;
// cannot be trivially substituted with `Binary::fmt()`,
; // because of specified formatting parameters
// so, additional formatting parameters have no effect
assert_eq!;
If, for some reason, transparency in trivial cases is not desired, it may be suppressed explicitly
either with the format_args!() macro usage:
use Debug;
// `format_args!()` obscures the inner type
;
// so, additional formatting parameters have no effect
assert_eq!;
Or by adding formatting parameters which cause no visual effects:
use Debug;
// `^` is centering, but in absence of additional width has no effect
;
// and so, additional formatting parameters have no effect
assert_eq!;
Example usage
use PathBuf;
use Debug;
;
] i32);
;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;