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),*)
}
};
}