Help needed for nested macro-by-example

Hi,

Goal:

I've spent the entire afternoon trying to write a macro-by-example that:

  • expands to an implementation item, impl From<T> for U block, for a given U w.r.t each T supplied
  • in addition, within the implementation item, adds documentation for the from() method

What I achieved now:

I can easily achieve the first goal, with something like this

macro_rules! _impl_from {
    ($to_type: ty, $($from_type: ty), +) => {
        $(
            impl From<$from_type> for $to_type {
                fn from(value: $from_type) -> Self {
                    //...omitted
                }
            }
        )+
    };
}

So for example, I can use _impl_from!(Foo, Bar, Xyz); to expands to these implementations

  • impl From<Bar> for Foo
  • impl From<Xyz> for Foo

Current challenge:

What I cannot achieve is, I want the macro also adds the documentation string. For example, I wish
_impl_foo!(Foo, Bar); would expands to

impl From<Bar> for Foo {
    #[doc = "Converts Bar to Foo"]
    fn from(value: Bar) -> Self {
        //...omitted
    }
}

But somehow I cannot work this out. I tried to add

#[doc = concat!("Converts ", stringify!($from_type), " to ", stringify!($to_type))

just above the line

fn from(value: $from_type) -> Self {

But it complains something like it's not expecting concat!.


It seems that writing down my challenge cleared my mind a bit. I've got it working now.

macro_rules! _fn_with_doc {
    ($doc: expr, $fn_body: item) => {
        #[doc = $doc]
        $fn_body
    };
}

macro_rules! impl_from_via {
    ($to_type:tt, $via_type:tt, $($from_type:tt), +) => {
        $(
            impl From<$from_type> for $to_type {
                _fn_with_doc!(
                    concat!(
                        "Converts `",
                        stringify!($from_type),
                        "` to `",
                        stringify!($to_type),
                        "` via `",
                        stringify!($via_type),
                        "`."
                    ),
                    fn from(color: $from_type) -> Self {
                        Self::from(<$via_type>::from(color))
                    }
                );
            }
        )+
    };
}