I'm new to macros, and have a one to which I need to pass a type constructor. This variant works ok:
macro_rules! derive_db_conversions_adl_1 {
($decl:ident) => {
impl<P1: serde::Serialize> crate::db::types::DbConversions
for $decl<P1>
{
...
}
};
}
but taking an :ident
, only accepts an unscoped name. I need to pass a scoped name. Unfortunately using :path
in lieu of :ident
does not compile. ie this:
macro_rules! derive_db_conversions_adl_1 {
($decl:path) => {
impl<P1: serde::Serialize> crate::db::types::DbConversions
for $decl<P1>
{
...
}
};
}
gives the error:
| for $decl<P1>
| ^ expected one of `!`, `+`, `where`, or `{`
|
How can this be done?
Thanks!
There is no stock solution to do this, so if you stick to macros you'll need either a "tt
muncher" or a proc macro, though both are elaborate.
Or else the HKT emulation pattern as recently described by @quinedot might be applicable.
You can take a list of ::
-separated idents Rust Playground
macro_rules! derive_db_conversions_adl_1 {
($($decl:ident)::+) => {
impl<P1: serde::Serialize> crate::db::types::DbConversions
for $($decl)::+<P1>
{
}
};
}
This definitely has problems if you get creative, like you can't do <A as Trait>::Type
, but for an internal macro it would be fine.
Edit: or you can use
the argument and rename it.
macro_rules! derive_db_conversions_adl_1 {
($decl:path) => {
use $decl as Type;
impl<P1: serde::Serialize> crate::db::types::DbConversions
for Type<P1>
{
}
};
}
(this needs to be scoped if you want to use the macro multiple times: Rust Playground)
2 Likes
if your macro only expands to an impl
block, a common workaround is to use an alias:
macro_rules! derive_db_conversions_adl_1 {
($decl:path) => {
// create an anonymous scope
const _: () = {
// create an local aliased import
use $decl as Decl;
impl<P1: serde::Serialize> crate::db::types::DbConversions
for Decl<P1>
{
}
};
};
}
Thanks all - I went with the ::
-separated idents approach.