#macro-rules #ident #macro #hash #concat

macro ident-mash

Mash idents together inside macro_rules!

1 unstable release

0.1.0 Aug 5, 2024

#1105 in Rust patterns

MIT license

13KB
285 lines

Ident-Mash

Have you ever had a bunch of identifiers that you "just want to mash together" inside a macro but don't want to resort to writing a procedural macro?

Ident-Mash has got you covered, because it takes care of the annoying proc macro part for you!

macro_rules! create_struct {
    ($name:ident) => {
        struct $name { ... }
        
        ident_mash::mash!{
            module = my_secret_ + :snake_case($name) + _module &
            constant = MY_SECRET_ + :upper_snake_case($name) + _CONST =>
            
            #[doc(hidden)]
            mod $module {
                const $constant: usize = 42;
                /* Secret stuff here */
            } }
        
         
    };
}

create_struct!(MyStruct);

Capabilities

As you can see from the example, creating more than one meta variable is allowed as well as using certain functions like :snake_case and "string literals" instead of idents. But there are other functions, which all take a list of idents or other functions. In fact, they support recursion.

Name Function
:upper_case: Turns everything uppercase
:lower_case Turns everything lowercase
:snake_case Uses the convert_case crate to convert the ident to snake_case
:upper_snake_case Same working mechanism but converts to UPPER_SNAKE_CASE
:pascal_case Same working mechanism but covnerts to PascalCase
:hash Computes a hash on the concatenated idents. Useful for generating deterministic random names

Extreme example: :hash(:snake_case(x + y + z) + x) + z + :hash(z)

More examples

The /tests directory contains tests that show off all the possible use cases of the macro, without making it too difficult to understand what's going on.

Bugs

It is possible to break the procedural macros or get it to produce unexpected results. How the macro works is it searches for the $meta_var pattern and replaces it with the generated ident.

But the meta_var name is the parameter you give as the first argument to mash!. For this reason, it is important to avoid giving a dynamic name to the meta variable.

E.G. don't do this:

macro_rules! dangerous {
    ($name:ident) => {
        struct $name { ... }
        
        ident_mash::mash!{
            $name = my_secret_ + :snake_case($name) + _module &
            constant = MY_SECRET_ + :upper_snake_case($name) + _CONST =>
            
            #[doc(hidden)]
            mod $$name {
                const $constant: usize = 42;
                /* Secret stuff here */
            } }
        
         
    };
}

dangerous!(MaliciousName);

This specific example doesn't even compile, but I think it illustrates the possible danger.

Future plans

More functions may be added in the future. If there is a function you'd like to see added, feel free to open a PR!

Dependencies

~0.6–1.1MB
~22K SLoC