Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to write a Rust macro that will expand into a function/method signature?

I would love to be able to something like the following:

macro_rules! impl_a_method(
    ($obj:ident, $body:block) => (
        fn a_method(foo: Foo, bar: Bar, baz: Baz) -> $obj $body
    )
)

// Implementation would look like:

impl_a_method!(MyType, {
    MyType {
        foo: foo.blah(),
        bar: bar.bloo(),
        baz: baz.floozy(),
    }
})

My real-world example features methods with much larger signatures which I have to implement in unique ways for 30+ different types.

I have tried something similar to the above macro, however I run into errors where rustc considers foo, bar and baz unresolved names at the expansion site (even though I'm sure the macro declaration lexically precedes the use).

Is it possible to do something like this?

If not, can you recommend an approach that would achieve something similar?

like image 433
mindTree Avatar asked Jul 23 '14 08:07

mindTree


People also ask

Are macros allowed in Rust?

The most widely used form of macros in Rust is the declarative macro. These are also sometimes referred to as “macros by example,” “ macro_rules! macros,” or just plain “macros.” At their core, declarative macros allow you to write something similar to a Rust match expression.

When to use macro vs function Rust?

Another important difference between macros and functions is that you must define macros or bring them into scope before you call them in a file, as opposed to functions you can define anywhere and call anywhere. Save this answer.

How do I make a macro in Rust?

To write a custom derive macro in Rust, we can use DeriveInput for parsing input to derive macro. We'll also use the proc_macro_derive macro to define a custom derive macro. More advanced procedural macros can be written using syn . Check out this example from syn 's repo.

What is Proc macro in Rust?

Procedural macros allow you to run code at compile time that operates over Rust syntax, both consuming and producing Rust syntax. You can sort of think of procedural macros as functions from an AST to another AST. Procedural macros must be defined in a crate with the crate type of proc-macro .


1 Answers

That's not possible due to macro hygiene. Any identifier introduced in the macro body is guaranteed to be different from any identifier at the macro call site. You have to provide all identifiers yourself, which somewhat defies the purpose of the macro:

impl_a_method!(MyType, (foo, bar, baz), {
    MyType {
        foo: foo.blah(),
        bar: bar.bloo(),
        baz: baz.floozy(),
    }
})

This is done by this macro:

macro_rules! impl_a_method(
    ($obj:ty, ($_foo:ident, $_bar:ident, $_baz:ident), $body:expr) => (
        fn a_method($_foo: Foo, $_bar: Bar, $_baz: Baz) -> $obj { $body }
    )
)

The only thing you're really saving here is writing types of method parameters.

like image 100
Vladimir Matveev Avatar answered Oct 08 '22 00:10

Vladimir Matveev