delegate-display 3.0.0

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

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

master CI badge crates.io badge Coverage Status dependencies badge

Examples

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<");
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<");
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 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");

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");
#[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()), "-");

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\")");
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");

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");
#[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