3.9 KiB
Custom attributes
The Debug
trait supports the following attributes:
- Container attributes
- Variant attributes
- Field attributes
Ignoring a field
You can use derivative to hide fields from a structure or enumeration Debug
implementation:
# extern crate derivative;
# use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug)]
struct Foo {
foo: u8,
#[derivative(Debug="ignore")]
bar: u8,
}
println!("{:?}", Foo { foo: 42, bar: 1 }); // Foo { foo: 42 }
Hiding newtypes
You can use derivative to automatically unwrap newtypes and enumeration variants with only one field:
# extern crate derivative;
# use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug="transparent")]
struct A(isize);
#[derive(Derivative)]
#[derivative(Debug)]
enum C {
Foo(u8),
#[derivative(Debug="transparent")]
Bar(u8),
}
println!("{:?}", A(42)); // 42
println!("{:?}", C::Bar(42)); // 42
// But:
println!("{:?}", C::Foo(42)); // Foo(42)
Format with
You can pass a field to a format function:
# extern crate derivative;
# use derivative::Derivative;
# mod path {
# pub struct SomeTypeThatMightNotBeDebug;
# pub mod to {
# pub fn my_fmt_fn(_: &super::SomeTypeThatMightNotBeDebug, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { unimplemented!() }
# }
# }
# use path::SomeTypeThatMightNotBeDebug;
#[derive(Derivative)]
#[derivative(Debug)]
struct Foo {
foo: u32,
#[derivative(Debug(format_with="path::to::my_fmt_fn"))]
bar: SomeTypeThatMightNotBeDebug,
}
The field bar
will be displayed with path::to::my_fmt_fn(&bar, &mut fmt)
where fmt
is the current Formatter
.
The function must the following prototype:
fn fmt(&T, &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>;
Custom bound
Usually, derivative will add a T: Debug
bound for each type parameter T
of the current type. If you do not want that, you can specify an explicit bound:
- Either on the type. This replaces all bounds:
# extern crate derivative;
# use derivative::Derivative;
# trait MyDebug {
# fn my_fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>;
# }
# use std::fmt::Debug;
#[derive(Derivative)]
#[derivative(Debug(bound="T: Debug, U: MyDebug"))]
struct Foo<T, U> {
foo: T,
#[derivative(Debug(format_with="MyDebug::my_fmt"))]
bar: U,
}
- Or on a field. This replaces the bound derivative guessed for that field. The example below is equivalent to the above:
# extern crate derivative;
# use derivative::Derivative;
# trait MyDebug {
# fn my_fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>;
# }
#[derive(Derivative)]
#[derivative(Debug)]
struct Foo<T, U> {
foo: T,
#[derivative(Debug(format_with="MyDebug::my_fmt", bound="U: MyDebug"))]
bar: U,
}
With bound=""
it is possible to remove any bound for the type. This is useful
if your type contains a Foo<T>
that is Debug
even if T
is not.
Packed structures
You can use derivative to implement Debug
on packed structures. Unlike the standard derive(debug)
, derivative does not require the structure itself to be Copy
, but like the standard derive(debug)
, it requires each (non-ignored) field to be Copy
.
# extern crate derivative;
# use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug)]
#[repr(C, packed)]
struct Foo {
foo: u8,
// `String` isn't `Copy` so it must be ignored to derive `Debug`
#[derivative(Debug="ignore")]
bar: String,
}