Anyway to create macro under struct?

Is there anyway to create macro under struct?

struct Context {
...
}

#[macro_export]
macro_rules! route {
...
}

To call

let ctx = Context();
ctx.route!();

Thank you

I suppose we would call that an associated macro, but no, there's no way to do that. The closest you can get is using it by module path.

Can you please give me an example?

How can that ever work?

If you consider the fact that route! doesn't exist in runtime while ctx doesn't exist when route! exist… it's really unclear what that construct meaning can be.

Remember that when types, variables and other such things come into existence macros are long-forgotten history.

What are you trying to achieve?

1 Like

You could have route! in a different namespace:

pub mod context {
    pub struct Context {
        /* … */
    }
    #[macro_export]
    macro_rules! __context__route {
        ($this:expr) => {
            /* … */
        };
    }
    pub use __context__route as route;
}

fn main() {
    let _ctx = context::Context { /* … */ };
    context::route!(_ctx);
}

(Playground)

But route! cannot be associated with the struct Context. And you will have to pass the "self" argument manually.


P.S.: But I assume moving everything to a module isn't what you want/need.

1 Like

@cuviper @VorfeedCanal @jbe
Sorry I made a mistake

It is suppose to be ctx.route!()
and NOT ctx::route!()

That doesn't change anything. Structs and macros still don't exist at the same point of time. Thus question of “what that construct is supposed to do” remains open.

Rust compiles programs in the following steps (roughly):

  1. First it reads source and looks on macros. Very little parsing is done at that point. Modules exist, but most of the other language constructs (types, variables, etc) don't.
  2. After macros are expanded and their content is replaced with expanded version the code is compiled.
  3. After compilation the program is executed. But by that time macros are long gone!

I suspect what you wanted to achieve is to declare type-specific macro. Which would only be defined for one type of struct for not for others. But because macro is expanded before types even exist it's not possible.

Worse: macros are, often, used to declare new types. Which means that to support what you want there needs to be circular dependency between expansion of macros, types definition and second expansion of macros.

This would create extremely convoluted and fragile system where simple cargo expand wouldn't be possible to make.

That's considered undesirable.

“Postfix macros” — macros which syntactically appear after an expression, like .await does — could exist in Rust, and have been proposed a few times. They don't currently exist, though.

Maybe it should be noted that it's possible to use an outer macro to introduce a new syntax. Consider the yield syntax from the async-stream crate: Usage example.

The same could be used to introduce all sort of new syntax constructs.

@cuviper @VorfeedCanal @jbe @kpreid
Is it possible with proc macro? Function like?

As other have noted that's not possible in Rust but you can, of course, create outer macro which would parse inner one.

What and how it interprets there it's entirely up to the outer macro (e.g. cpp uses it to write a tiny bit of C++ in the middle of Rust code and inline_python does the same with python).