#display #derive-debug #debugging #enums #derive #macro

macro build delegate-display

derive(Display, Debug) for structs/enums with one member

12 stable releases

3.0.0 Oct 15, 2024
2.1.1 Sep 28, 2023
1.0.8 Apr 3, 2023
1.0.7 Mar 4, 2023
1.0.1 Feb 28, 2023

#469 in Build Utils

Download history 3188/week @ 2024-08-27 3957/week @ 2024-09-03 3262/week @ 2024-09-10 2976/week @ 2024-09-17 3262/week @ 2024-09-24 2791/week @ 2024-10-01 2674/week @ 2024-10-08 3482/week @ 2024-10-15 3003/week @ 2024-10-22 3481/week @ 2024-10-29 3433/week @ 2024-11-05 3727/week @ 2024-11-12 4460/week @ 2024-11-19 4224/week @ 2024-11-26 4378/week @ 2024-12-03 2838/week @ 2024-12-10

16,707 downloads per month
Used in 30 crates (2 directly)

MIT license

39KB
620 lines

Lets you derive fmt traits on types wrapping types that already implement them.

master CI badge crates.io badge Coverage Status dependencies badge

Examples

Newtype structs
struct SomeType;
impl core::fmt::Display for SomeType {
  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    f.write_str(">foo<")
  }
}

#[derive(DelegateDisplay)]
struct Foo(SomeType);

assert_eq!(format!("{}", Foo(SomeType)), ">foo<");
Structs with 0..=1 fields
struct SomeType;
impl core::fmt::Debug for SomeType {
  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    f.write_str(">foo<")
  }
}

#[derive(DelegateDebug)]
struct Foo { some_field: SomeType }

assert_eq!(format!("{:?}", Foo { some_field: SomeType }), ">foo<");
Enums with 0..=1 variants each
struct SomeType;
struct AnotherType;

impl core::fmt::Display for SomeType {
  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    f.write_str(">foo<")
  }
}
impl core::fmt::Display for AnotherType {
  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    f.write_str(">bar<")
  }
}

#[derive(DelegateDisplay)]
enum MyEnum {
  Foo,
  Bar(SomeType),
  Qux { baz: AnotherType }
}

assert_eq!(format!("{}", MyEnum::Bar(SomeType)), ">foo<");
assert_eq!(format!("{}", MyEnum::Qux { baz: AnotherType }), ">bar<");
Generics

Generics are handled automatically for you.

#[derive(DelegateDisplay)]
struct MyStruct<T>(T);

#[derive(DelegateDisplay)]
enum MyEnum<A, B> {
  A(A),
  B { value: B },
}

assert_eq!(format!("{}", MyStruct(50)), "50");
assert_eq!(format!("{}", MyEnum::<u8, i8>::A(75)), "75");
assert_eq!(format!("{}", MyEnum::<u8, i8>::B { value: -1 }), "-1");
Structs & enums with 2+ fields

The field being delegated to must be marked with the appropriate attribute.


#[derive(DelegateDisplay)]
struct MyStruct<T> {
  label: String,
  #[ddisplay]
  value: T,
}

#[derive(DelegateDebug)]
enum MyEnum {
  Foo(#[ddebug] String, u8),
  Bar { baz: u8, #[ddebug] qux: u8 }
}

let my_struct = MyStruct { label: "foo".into(), value: 42 };
assert_eq!(format!("{}", my_struct), "42");

let my_enum = MyEnum::Foo(".".into(), 1);
assert_eq!(format!("{:?}", my_enum), "\".\"");

let my_enum = MyEnum::Bar { baz: 2, qux: 3 };
assert_eq!(format!("{:?}", my_enum), "3");
Empty structs
#[derive(DelegateDebug, DelegateDisplay)]
struct Foo;

#[derive(DelegateDebug, DelegateDisplay)]
struct Bar{}

#[derive(DelegateDebug, DelegateDisplay)]
struct Qux();

assert_eq!(format!("{}-{:?}", Foo, Foo), "-");
assert_eq!(format!("{}-{:?}", Bar{}, Bar{}), "-");
assert_eq!(format!("{}-{:?}", Qux(), Qux()), "-");
Typed delegations

Can be useful for further prettifying the output.

/// Some type that `Deref`s to the type we want to use in our formatting, in this case, `str`.
#[derive(Debug)]
struct Wrapper(&'static str);
impl std::ops::Deref for Wrapper {
  type Target = str;
  fn deref(&self) -> &Self::Target {
    self.0
  }
}

#[derive(DelegateDebug)]
#[ddebug(delegate_to(str))] // ignore `Wrapper` and debug the `str` it `Deref`s instead
struct Typed(Wrapper);

#[derive(DelegateDebug)] // Included for comparison
struct Base(Wrapper);

assert_eq!(format!("{:?}", Typed(Wrapper("foo"))), "\"foo\"");
assert_eq!(format!("{:?}", Base(Wrapper("bar"))), "Wrapper(\"bar\")");
Custom generic bounds
struct CopyDisplayable<T>(T); // Implements Deref

impl<T: Copy> Display for CopyDisplayable<T> {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    unimplemented!("Nonsense generic bound - base bounds don't work.");
  }
}

// Without these options the implementation would have a predicate of `CopyDisplayable<T>: Debug` which would
// effectively mean `T: Copy`; we can transform it to `T: Display` because `CopyDisplayable` derefs to `T`.
#[derive(DelegateDisplay)]
#[ddisplay(bounds(T: Display), delegate_to(T))]
struct Displayable<T>(CopyDisplayable<T>);

let dbg = Displayable::<String>(CopyDisplayable("cdbg".into()));
assert_eq!(format!("{}", dbg), "cdbg");
Multiple traits at once

Instead of re-parsing your struct/enum multiple times, you can instead derive DelegateFmt. It supports every individual macro's attribute along with dany as a catch-all default.

struct Wrapper(u8); // implements Deref

#[derive(DelegateFmt)]
#[dfmt(dany(delegate_to(u8)), ddebug, ddisplay, dbinary)]
struct MyStruct(#[dany] Wrapper, #[dbinary] Wrapper);

assert_eq!(format!("{:?}", MyStruct::new(1, 2)), "1");
assert_eq!(format!("{}", MyStruct::new(3, 4)), "3");
assert_eq!(format!("{:b}", MyStruct::new(5, 6)), "110");
Invalid inputs
#[derive(delegate_display::DelegateDebug)]
struct TooManyFields1 {
  foo: u8,
  bar: u8, // No fields marked with `#[ddebug]` or `#[dany]`
}
#[derive(delegate_display::DelegateDebug)]
struct TooManyFields2(u8, u8); // No fields marked with `#[ddebug]` or `#[dany]`
#[derive(delegate_display::DelegateDebug)]
enum SomeEnum {
  A, // this is ok
  B(u8), // this is ok
  C { foo: u8 }, // this is ok
  D(u8, u8), // ERR: No fields marked with `#[ddebug]` or `#[dany]`
  E { foo: u8, bar: u8 } // ERR: No fields marked with `#[ddebug]` or `#[dany]`
}
#[derive(delegate_display::DelegateDebug)]
union Foo { bar: u8 } // Unions are not supported
struct NonDebug;

#[derive(DelegateDebug)]
struct Foo<A, B>(A, B);

format!("{:?}", Foo(NonDebug, 1)); // NonDebug does not implement Debug

Dependencies

~310–760KB
~17K SLoC