How to Use Macro Across Module Files in React

Nilesh Katuwal Feb 02, 2024
  1. Rust Macros
  2. Macros Across Crates in Rust
  3. Macros Within the Same Crate in Rust
How to Use Macro Across Module Files in React

In this article, we will learn about using macro across module files in Rust.

Rust Macros

Rust provides great macro support. For example, metaprogramming, which is enabled through macros, involves writing code that writes other code.

Macros offer capability comparable to functions but without the associated runtime cost. As macros are extended at compile-time, build time costs are associated.

Rust macros differ significantly from C macros. For example, Rust macros are applied to the token tree, while C macros substitute text.

Syntaxes:

*MacroRulesDefinition* :
  `macro_rules` `!` [IDENTIFIER] *MacroRulesDef*
MacroRules :
   MacroRule ( ; MacroRule )* ;?

MacroRule :
   MacroMatcher => MacroTranscriber

Macros Across Crates in Rust

A crate includes a hierarchy of module scopes. Any object within a crate has a canonical module path indicating its location within the module tree.

At the top level of this tree, there is an anonymous module. A Rust source file specifies a module whose name and location in the module tree of the current crate are defined externally: either by an explicit Module item in a referenced source file.

It could also be the name of the crates themselves. Every source file is a module.

However, not every module needs its source file: module definitions can be layered within a single source file.

Crate util:

#[macro_export]
macro_rules! foo {
    () => ()
}

Crate user:

use util::foo;

foo!();

Note that macros always reside on the top level of a crate when using this strategy. Even if foo is contained within a mod bar, the user crate must still write use util::foo; and not use util::bar::foo;.

You can export a macro from a module of your crate by using pub use.

Macros Within the Same Crate in Rust

foo::bar!();

mod foo {
    macro_rules! bar {
        () => ()
    }

    pub(crate) use bar;
}

foo::bar!();

The macro can be imported and used as any other object with pub use. And unlike the older way, this does not depend on source code order, so you can use the macro before it has been written.

Each macro has a name and one or more rules. Each rule consists of two parts: a matcher, which describes the syntax it matches, and a transcriber, which describes the syntax that will be substituted for a successfully matched invocation.

Delimiters must encompass both the matcher and the transcriber. Expressions, Statements, traits, impls, foreign items, types, and patterns can be expanded via macros.