Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with this Rust macro?

Tags:

macros

rust

I'm trying to write a macro that generates a From impl for an enum by wrapping the type in a certain variant.

I've come up with this:

macro_rules! variant_derive_from {
    ($enum:ty:$variant:ident($from:ty)) => {
        impl From<$from> for $enum {
            fn from(thing: $from) -> $enum { return $enum::$variant(thing) }
        }
    };
}

However, whenever I try to actually use this macro I get the following error:

error: expected expression, found `B`
|             fn from(thing: $from) -> $enum { $enum::$variant(thing) }
|                                               ^^^^

I couldn't figure out why this might be happening, so I ran a build with macro tracing on, and the macro apparently expands to the following (dummy types, of course):

impl From < A > for B { fn from ( thing : A ) -> B { B :: AVariant ( thing ) } }

When pasting this directly into the code, it compiles successfully. What gives??

Here's a full example of the error.

like image 822
AlphaModder Avatar asked Dec 02 '17 09:12

AlphaModder


People also ask

Are macros allowed on 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.

Are Rust macros like Lisp macros?

Rust's macros are very good. They act like Lisp's macros, unlike Haskell's. The fact that Rust has type-classes (“traits”) and sum types (“enums”) and pattern matching is very attractive. Making orphan instances package-wide rather than module-wide is a very good decision.

Is macro_rules a macro?

macro_rules allows users to define syntax extension in a declarative way. We call such extensions "macros by example" or simply "macros". Each macro by example has a name, and one or more rules.

How does Rust macro work?

Rust provides a powerful macro system that allows metaprogramming. As you've seen in previous chapters, macros look like functions, except that their name ends with a bang ! , but instead of generating a function call, macros are expanded into source code that gets compiled with the rest of the program.


1 Answers

A ty placeholder only works as type, not as a namespace. Using ident instead should work just fine in your example.

ident doesn't accept paths ("foo::Bar") though (and using path also doesn't seem to work in this case); you should be able to workaround it by manually constructing paths like matching this: $enum:ident $(:: $enum_path:ident)* (use it like this: $enum $(:: $enum_path)*).

like image 112
Stefan Avatar answered Sep 20 '22 17:09

Stefan