compose-idents
A macro for generating new identifiers (names of variables, functions, traits, etc) by concatenating one or more arbitrary parts and applying other manipulations.
Motivation
Rust's declarative macros do not allow generating new identifiers, because they are designed to operate on the syntactic level (as opposed to the lexical level) using simple pattern matching.
For example the following code won't work:
my_macro!;
assert_eq!;
compose-idents resolves this limitation:
use compose_idents;
my_macro!;
assert_eq!;
Usage
This section contains various usage examples. For even more usage examples look into tests/ directory
of the repository.
Full example
This example includes all the features of the macro:
use compose_idents;
compose_idents!;
// It's possible to use arguments of declarative macros as parts of the identifiers.
outer_macro!;
global_var_macro!;
global_var_macro!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
Generating tests for different types
More practical example for how to auto-generate names for macro-generated tests for different data types:
use Add;
use compose_idents;
generate_add_tests!;
test_add_u8;
test_add_u32;
test_add_u64;
Formatting docstrings for generated functions
It's possible to format strings in doc-attributes (and also any literal strings) using %alias% syntax. It is useful
for generating docstrings for generated functions.
In this particular example we are generating addition functions that work at compile time for different types
(as core::ops::Add can't be used in generic const-functions). Notice, in addition to the function name,
the docstring is also formatted so that it mentions the type of the function:
use compose_idents;
generate_add!;
generate_add!;
The above example expands into this:
use compose_idents;
///Adds two arguments of type `u32` at compile time.
const
///Adds two arguments of type `u64` at compile time.
const
Functions
| Function | Description |
|---|---|
upper(arg) |
Converts the arg to upper case. |
lower(arg) |
Converts the arg to lower case. |
snake_case(arg) |
Converts the arg to snake_case. |
camel_case(arg) |
Converts the arg to camelCase. |
hash(arg) |
Hashes the arg deterministically within a single macro invocation. |
Alternatives
There some other tools and projects dedicated to identifier manipulation:
- A macro from Nightly Rust that allows to concatenate identifiers. It is limited in functionality and nowhere near to be stabilized: https://doc.rust-lang.org/std/macro.concat_idents.html
- A very similar macro that doesn't support multiple aliases and is not maintained: https://github.com/DzenanJupic/concat-idents
- A macro that allows to define and refer to unique temporary variables: https://crates.io/crates/templest
Development
The following standards are followed to maintain the project: