2 unstable releases

Uses new Rust 2024

new 0.2.0 Mar 6, 2026
0.1.0 Mar 6, 2026

#586 in Procedural macros

MIT license

16KB
193 lines

format-attr

document: https://docs.rs/format-attr

A Rust proc-macro crate that provides custom derive macros for implementing Display and Debug traits with custom format strings.

Features

  • DisplayAttr - Derive std::fmt::Display with a custom format string
  • DebugAttr - Derive std::fmt::Debug with a custom format string
  • DisplayAsDebug - Implement Display by delegating to the existing Debug implementation
  • Support for separate format strings via #[fmt_display(...)] and #[fmt_debug(...)]
  • Fallback to shared #[fmt(...)] attribute

Usage

Add this to your Cargo.toml:

[dependencies]
format-attr = "0.1.0"

Basic Example

use format_attr::{DisplayAttr, DebugAttr};

#[derive(DisplayAttr, DebugAttr)]
#[fmt("Point({}, {})", x, y)]  // `self.` prefix is optional for simple field access
struct Point {
    x: i32,
    y: i32,
}

let p = Point { x: 10, y: 20 };
assert_eq!(format!("{}", p), "Point(10, 20)");
assert_eq!(format!("{:?}", p), "Point(10, 20)");

Note: You can omit the self. prefix for simple field names. If you need to call methods or use complex expressions, you can still use self.field.method() syntax.

Inline Field Names

You can also use field names directly inside the format string:

use format_attr::{DisplayAttr, DebugAttr};

#[derive(DisplayAttr, DebugAttr)]
#[fmt("Point({x}, {y})")]  // {x} and {y} are automatically replaced with field values
struct Point {
    x: i32,
    y: i32,
}

let p = Point { x: 10, y: 20 };
assert_eq!(format!("{}", p), "Point(10, 20)");

Format specifiers are also supported:

use format_attr::DisplayAttr;

#[derive(DisplayAttr)]
#[fmt("Name: {name:>10}, Age: {age:?}")]
struct Person {
    name: String,
    age: u32,
}

let p = Person { name: "Alice".to_string(), age: 30 };
assert_eq!(format!("{}", p), "Name:      Alice, Age: 30");

Separate Format Strings

Use #[fmt_display(...)] and #[fmt_debug(...)] for different output:

use format_attr::{DisplayAttr, DebugAttr};

#[derive(DisplayAttr, DebugAttr)]
#[fmt_display("User: {}", name)]
#[fmt_debug("User {{ name: {}, age: {} }}", name, age)]
struct User {
    name: String,
    age: u32,
}

let u = User { name: "Alice".to_string(), age: 30 };
assert_eq!(format!("{}", u), "User: Alice");
assert_eq!(format!("{:?}", u), "User { name: Alice, age: 30 }");

DisplayAsDebug

When you want Display to use the same output as Debug:

use format_attr::DisplayAsDebug;

#[derive(Debug, DisplayAsDebug)]
struct Value(i32);

let v = Value(42);
assert_eq!(format!("{}", v), "Value(42)");
assert_eq!(format!("{:?}", v), "Value(42)");

Attribute Priority

Derive Macro Priority 1 Priority 2 (fallback)
DisplayAttr #[fmt_display(...)] #[fmt(...)]
DebugAttr #[fmt_debug(...)] #[fmt(...)]

License

MIT

Dependencies

~115–490KB
~12K SLoC