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
16,707 downloads per month
Used in 30 crates
(2 directly)
39KB
620 lines
Lets you derive fmt
traits on types wrapping types that already implement them.
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