Crate fmt_derive

source ·
Expand description

More robust and versatile implementation of derive(Debug) and derive(Display). Unlike the version of derive(Debug) in the standard library, these macros will always successfully generate an implementation - even if a member does not implement Debug/Display. In that case, the generated implementation will print a replacement string of the form <TypeName>.

More Robust

These derive macros always work, even when derive(std::fmt::Debug) fails.

// a type that implements neither `Debug` nor `Display`
struct Unprintable;

#[derive(fmt_derive::Debug, fmt_derive::Display)]
struct Printable(Unprintable);

fn main() {
  // error[E0277]: `Unprintable` doesn't implement `Debug`
  // println!("{:?}", Unprintable);

  assert_eq!(format!("{:?}", Printable(Unprintable)), "Printable(<Unprintable>)");

  // deriving display is often more useful with a custom format expression, but will silently fall back to the same
  // behavior as `Debug`
  assert_eq!(format!("{}", Printable(Unprintable)), "Printable(<Unprintable>)");
}

Drop in Usage

Anything that derives [std::fmt::Debug] or core::fmt::Debug can derive fmt_derive::Debug instead without any changes required.

However, both cannot be used at the same time, as their names clash:

// error[E0252]: the name `Debug` is defined multiple times
use fmt_derive::Debug;
use core::fmt::Debug;

The same problem exists for Display:

// error[E0252]: the name `Display` is defined multiple times
use fmt_derive::Display;
use core::fmt::Display;

If you encounter this problem, there is a simple solution: use fmt_derive::Debug; also pulls in the [std::fmt::Debug]/core::fmt::Debug trait, there is no need to use the standard library Debug.

use fmt_derive::Debug; // replace `use std::fmt::Debug;` and `use core::fmt::Debug;`

struct Unprintable;

#[derive(Debug)]
struct Printable(Unprintable);

fn main() {
  // error[E0277]: `Unprintable` doesn't implement `Debug`
  // println!("{:?}", Unprintable);

  assert_eq!(format!("{:?}", &Printable(Unprintable) as &dyn Debug), "Printable(<Unprintable>)");
}

More Versatile

The derived implementation can be easily customized using additional attributes.

Custom Format Expressions

A custom representation can be quickly derived using a format expression for the whole structure, enumeration, or untagged unions. This is the expected case when deriving Display or when a member needs to be formatted in a special manner:

use fmt_derive::{Debug, Display};

#[derive(Display, Debug)]
#[debug("T<0x{:X}>", self.0)]
#[display("A thing that sits on the number {}", self.0)]
struct Thing(u32);

fn main() {
  assert_eq!(format!("{:?}", Thing(0xF7A)), "T<0xF7A>");
  assert_eq!(format!("{}", Thing(42)), "A thing that sits on the number 42");
}

Custom Format Expressions for Enumeration Variants

For enumerations, variants can also be customized:

use fmt_derive::Debug;

#[derive(Debug)]
enum Thing{
  // tuple members are exposed as `_0`, `_1`, and so forth
  #[debug("Thing::VariantA(0x{:X}, {})", _0, _1)]
  VariantA(u32, u32),
  // struct members are exposed under their name
  #[debug("Thing::VariantB({})", x)]
  VariantB{
    x: u32,
    unused: u32,
  }
}

fn main() {
  assert_eq!(format!("{:?}", Thing::VariantA(0xF7A, 42)), "Thing::VariantA(0xF7A, 42)");
  assert_eq!(format!("{:?}", Thing::VariantB{x: 42, unused: 0}), "Thing::VariantB(42)");
}

Custom Format Expressions for Individual Fields

Or by customizing an individual field:

use fmt_derive::Debug;

#[derive(Debug)]
struct Thing(#[debug("0x{:X}", self.0)] u32);

fn main() {
  assert_eq!(format!("{:?}", Thing(0xF7A)), "Thing(0xF7A)");
}

Ignoring a Field

Although it is possible to derive a debug message for any field, it is sometimes preferable to not print a field at all:

use fmt_derive::Debug;

#[derive(Debug)]
struct Function(#[debug(ignore)] fn());

fn main() {
  assert_eq!(format!("{:?}", Function(main)), "Function");
}

Traits

  • The trait and macro from the standard library. Only the trait is actually exposed by this crate. ? formatting.
  • The trait and macro from the standard library. Only the trait is actually exposed by this crate. Format trait for an empty format, {}.

Derive Macros

  • Derive implementations of Debug for arbitrary structs and enums (unions are supported only with a top-level format directive). useing fmt_derive::Debug, will also pull in the core::fmt::Debug/[std::fmt::Debug] trait (but the macro of the same name will be replaced with this one).
  • The trait and macro from the standard library. Only the trait is actually exposed by this crate. Derive macro generating an impl of the trait Debug.
  • Derive implementations of Display for arbitrary structs and enums (unions are supported only with a top-level format directive).. useing fmt_derive::Display, will also pull in the core::fmt::Display/[std::fmt::Display] trait (but the macro of the same name will be replaced with this one).