Macro rules help

What I have:


#[macro_export]
macro_rules! mm_box_decl {
    {
        $outer_name:ident ; $expr:expr
    } => {
        pub struct $outer_name {
            inner: Box<dyn $expr>,
        }

        impl Deref for $outer_name {
            type Target = $expr;

            fn deref(&self) -> &Self::Target {
                self.inner.deref()
            }
        }

        impl DerefMut for $outer_name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                self.inner.deref_mut()
            }
        }
    }
}

How I am trying to call it:

mm_box_decl!(Blah, Foo_T<Bar>)

where we have:

pub trait Foo_T<Arg> {
... }

I am getting an error of: "comparison operators cannot be chained". I think it has something to do with the way I'm trying to parse the trait as a $expr:expr.

Thanks!

The syntactic problem will be solved if you pass Foo_T::<Bar> instead, but then a more severe problem will surface: you are using expr fragment as a type, and cannot do that. Once captured as expr, it can only be in expression positions.

Is there anything here:

https://veykril.github.io/tlborm/decl-macros/macros-methodical.html

that matches 'trait' ? I see $expr and $ty but no $trait.

#[macro_export]
macro_rules! mm_box_decl {
    {
        $outer_name:ident ; $($tt:tt)*
    } => {
        pub struct $outer_name {
            inner: Box<dyn $($tt)*>,
        }

        impl Deref for $outer_name {
            type Target = dyn $($tt)*;

            fn deref(&self) -> &Self::Target {
                self.inner.deref()
            }
        }

        impl DerefMut for $outer_name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                self.inner.deref_mut()
            }
        }

    }
}

appears to work; tt munchers again ?

To match a reference to a trait, such as you would have in a trait bound, you want path, which matches a TypePath.

3 Likes

Here an example with a path metavariable as @jameseb7 suggested[1]:

macro_rules! mm_box_decl {
    {
        $outer_name:ident ; $t:path
    } => {
        pub struct $outer_name {
            inner: Box<dyn $t>,
        }

        impl Deref for $outer_name {
            type Target = $t;

            fn deref(&self) -> &Self::Target {
                self.inner.deref()
            }
        }

        impl DerefMut for $outer_name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                self.inner.deref_mut()
            }
        }
    }
}

Playground.


  1. While I was still on the playground :slightly_smiling_face: ↩ī¸Ž

2 Likes