Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a macro simplify trait impl?

Tags:

rust

I want to simplify files and indention levels for implementing several Traits for a given struct. Is there a way I can do something like this?

struct Foo { /* ommitted */ }

impl(Default(Foo)) fn default() -> Self {
  /* do something */
}

Obviously, it is possible to write

impl Default for Foo {
  fn default() -> Self {
    /* do something */
  }
}

but the enclosing text provides no more value than the macro I hope exists. Although I am new to Rust, I am well aware of (and frequently use)

#[derive(Default)]

but I am looking for a way to simplify actually implementing many traits. I would consider the following clear as well, but AFAIK it is not legal Rust. Note that the following is similar to rust-lang #1250:

impl Foo {
  type Index::Output = Bar;
  trait Default fn default() -> Self {
    // ...
  }
  trait Debug fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    // ...
  }
  trait Display fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    // ...
  }
  trait Index<usize> fn index(&self, (r, c): (usize, usize)) -> &Self::Index::Output {
    // ...
  }
  fn my_custom_thing() -> () {
    // ...
  }
}
like image 515
Horati Avatar asked Mar 11 '26 08:03

Horati


1 Answers

Whenever I tried something like this, I found that it was easier to just write out the impls.

Thus, I would advise against it. But if you insist, you could start out with the following:

macro_rules! quick_impl {
    ($structname: ident, Default, $($t:tt)*) => {
          impl Default for $structname {
              fn default() -> Self {
                  Self {$($t)*}
              }
          }
    };
    ($structname: ident, Debug, $($field:ident),*) => {
        impl std::fmt::Debug for $structname {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                f.debug_struct(stringify!($tyname))
                $(
                    .field(stringify!($field), &self.$field)
                )*
                .finish()
            }
        }
    };
    // here be more implementations
}

Usable like this:

struct S {
    a: usize,
    b: bool,
    c: char,
}

quick_impl!(S, Default, a:1, b:true, c:'c');
quick_impl!(S, Debug, a, b, c);

This macro goes a step further in that you do not have to say trait or fn in the arguments (as this is clear anyway).

like image 74
phimuemue Avatar answered Mar 12 '26 22:03

phimuemue