Is there a way to pass a macro metavar as a part of a macro invocation?

⚓ Rust    📅 2026-02-24    👤 surdeus    👁️ 1      

surdeus

I tried something like this.

#![feature(macro_metavar_expr)]

use std::fmt;

macro_rules! e_match {
    (<> $self:expr, $inner:ident, $($expr:tt)*) => {
        e_match!{
            <>,
            variants=[
                (E1, $($expr)*),
                (E2, $($expr)*),
            ], $self, $inner
        }

    };
    (<>, variants=[$(($v_id:ident, $($v_expr:tt)*),)+], $self:expr, $inner:ident) => {
        {
            macro_rules! e_match_ {
                ($$self:expr, $$inner:ident) => {
                    match $self {
                        $(
                            E::$v_id($inner)  => $($v_expr)*,
                        )+
                    }
                };
            }
            e_match_!($self, $inner)
        }
    };
}

#[derive(Debug, PartialEq)]
enum E {
    E1(u8),
    E2(u8),
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq)]
enum ETag {
    E1,
    E2,
}


impl ETag {
    fn from_e(e: &E) -> Self {
        e_match!(<> e, _inner, Self::$v_id)
    }
}

impl fmt::Display for E {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        e_match!{
            <> self, _inner,
            f.write_str(concat!(stringify!(E), "::", stringify!($v_id)))
        }
    }
}

The first invocation fails to compile. And the second stringifies $v_id instead of the actual variant name.

1 post - 1 participant

Read full topic

🏷️ Rust_feed