Motivation: Ho un’interfaccia grossa e ho n sistemi che la implementano, ma la implementano in modo diverso

Solution in short: Scrivo una macro del tipo apply_whatever che prende in input l’identifier di una macro mac (e il resto delle cose che gli servono) e si espande mettendo la chiamata a mac e passandoci dentro i token con cui fare generare il codice vero (usando mac). In questo modo basta scrivere una volta le definizioni e poi per ogni impl diversa si chiama apply e si passa una macro che specifica solo la “traduzione” da interfacci

Interfaccia che prende $mac come parametro

macro_rules! apply_imports_definitions {
    ($mac:ident, $linker:expr, $namespace:ident) => {
        $mac! { $linker ; $namespace:
            // Log
            _panic => panic(),
            _info => info(buf: i64),
            _warn => warn(buf: i64),
            _error => error(buf: i64),
            // ...
        }
    }
}

Macro che accetta i token che passa apply_imports_definition

macro_rules! link_fn {
    ($linker:expr; $(
        $namespace:ident: $($name:ident => $ff:ident($($arg:ident: $typ:ty),*),)*);
    *) => {
        $($($linker
            .func_wrap(stringify!($namespace), stringify!($name), host_fn!($ff($($arg: $typ),*)))
            .unwrap());*
        )*
    }
}

Chiamata ad apply

apply_imports_definitions!(link_fn, linker, radon);

Nota: host_fn è un’altra macro in questa forma, potrebbe essere direttamente in link_fn volendo

macro_rules! host_fn {
    ($ff:ident($($arg:ident: $typ:ty),*)) => {
        |mut caller: Caller<'_, MInstanceData<R>>, $($arg: $typ),*| {
            // stuff here
            let mut h = /* other stuff */;
            h.$ff($($arg),*)
        }
    };
}