#display #traits #derive #impl #helper #proc-macro #format

macro derive_display

A convenient attribute to derive Display implementation from another trait implementation. Currently supports ToTokens.

2 releases

0.0.3 Jun 24, 2024
0.0.2 Jun 24, 2024

#383 in Procedural macros

MIT license

10KB

derive_display

GitHub Stars Crates.io Total Downloads GitHub Issues Current Version

A convenient attribute to derive Display implementation from another trait implementation. Currently supports ToTokens.

Usage

To use this proc-macro in your project, add the following to your Cargo.toml:

[dependencies]
derive_display = "0.0.2" # use the latest version, or a specific one if needed

Then wherever you want to derive Display from another implementation, use the #[derive_display] attribute before that implementation:

use derive_display::derive_display;

#[derive_display]
impl SomeTrait for MyStruct {
    fn some_trait(&self, foo: &mut Bar) {
        ...
    }
}

This means you can simply tag the implementation you wish with the attribute, and nothing else needs to be done. Simple as that.

Currently supported implementations

Implementation Description
ToTokens Simply uses whatever ToTokens returns as the display representation

Note: Support for generics and some usual edge cases are built in, so it should be as easy as plug in and use. Issues and PRs are welcome if it doesn't cover something yet!

Example

Let's say we have a struct and we need to provide a Display implementation. If it so happens that we already have a suitable implementation that formats a string for some other purpose, and that would suffice, you can simply tag the impl with the #[derive_display] attribute:

use derive_display::derive_display;
use quote::ToTokens;

struct MyStruct {
    x: i32,
    y: i32,
}

#[derive_display]
impl ToTokens for MyStruct {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        let content = format!("MyStruct: x = {}, y = {}", self.x, self.y);
        content.to_tokens(tokens);
    }
}

This expands to the following implementation, in addition to the source implementation:

impl Display for MyStruct {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let s = &self;
        let q = quote!(#s); // <-- this is for the `ToTokens` derive
        f.write_fmt(format_args!("{}", q.to_string()))
    }
}

This results in a Display implementation without any explicit busywork. Without this crate (or some other way of achieving the same), the developer would have to manually write out something like the above implementation of Display, which is pretty boring and redundant, since it just uses some method of forwarding another implementation.

The Problem

In Rust, types do not automatically implement the Display trait, which is required for types to be printable. This can feel like unnecessary busywork, if we simply want to print something sufficiently representing in a more human-readable form, especially if we already have implementations for traits that construct suitable formatted strings representing our struct.

There's the actual derive proc-macro for display (i.e #[derive(Display)] for structs), but that's not always ideal, and sometimes the struct just has members incompatible with that macro.

This crate provides a solution to this by allowing developers to derive the Display implementation from an existing trait implementation simply by using a simple attribute.

This creates a Display implementation with minimal effort, and removes the need for verbose and manual Display implementation, especially when it's similar to already implemented ToTokens trait.

Support

Whether you use this project, have learned something from it, or just like it, please consider supporting it by buying me a coffee, so I can dedicate more time on open-source projects like this :)

Buy Me A Coffee

License

You can check out the full license here

This project is licensed under the terms of the MIT license.

Dependencies

~235–670KB
~16K SLoC