Skip to content

Commit ad618c9

Browse files
committed
unstable book; document macro_metavar_expr_concat
1 parent da83217 commit ad618c9

File tree

3 files changed

+166
-0
lines changed

3 files changed

+166
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# `macro_metavar_expr_concat`
2+
3+
The tracking issue for this feature is: [#124225]
4+
5+
------------------------
6+
7+
8+
`#![feature(macro_metavar_expr_concat)]` provides a more powerful alternative to [`concat_idents!`].
9+
10+
> This feature is not to be confused with [`macro_metavar_expr`] or [`concat_ident`].
11+
12+
> This is an experimental feature; it and its syntax will require a RFC before stabilization.
13+
14+
15+
### Overview
16+
17+
`macro_rules!` macros cannot create new identifiers and use them in ident positions.
18+
A common use case is the need to create new structs or functions. The following cannot be done[^1]:
19+
20+
```rust,compile_fail
21+
macro_rules! create_some_structs {
22+
($name:ident) => {
23+
// Invalid syntax
24+
struct First_$name;
25+
// Also invalid syntax
26+
struct Second_($name);
27+
// Macros are not allowed in this position
28+
// (This restriction is what makes `concat_idents!` useless)
29+
struct concat_ident!(Third_, $name);
30+
}
31+
}
32+
# create_some_structs!(Thing);
33+
```
34+
35+
`#![feature(macro_metavar_expr_concat)]` provides the `concat` metavariable to concatenate idents in ident position:
36+
37+
```rust
38+
#![feature(macro_metavar_expr_concat)]
39+
# #![allow(non_camel_case_types, dead_code)]
40+
41+
macro_rules! create_some_structs {
42+
($name:ident) => {
43+
struct ${ concat(First_, $name) };
44+
struct ${ concat(Second_, $name) };
45+
struct ${ concat(Third_, $name) };
46+
}
47+
}
48+
49+
create_some_structs!(Thing);
50+
```
51+
52+
This macro invocation expands to:
53+
54+
```rust
55+
# #![allow(non_camel_case_types, dead_code)]
56+
struct First_Thing;
57+
struct Second_Thing;
58+
struct Third_Thing;
59+
```
60+
61+
### Syntax
62+
63+
This feature builds upon the metavariable expression syntax `${ .. }` as specified in [RFC 3086] ([`macro_metavar_expr`]).
64+
`concat` is available like `${ concat(items) }`, where `items` is a comma separated sequence of idents and/or string literals.
65+
66+
### Examples
67+
68+
#### Create a function or method with a concatenated name
69+
70+
```rust
71+
#![feature(macro_metavar_expr_concat)]
72+
# #![allow(non_camel_case_types, dead_code)]
73+
74+
macro_rules! make_getter {
75+
($name:ident, $field: ident, $ret:ty) => {
76+
impl $name {
77+
pub fn ${ concat(get_, $field) }(&self) -> &$ret {
78+
&self.$field
79+
}
80+
}
81+
}
82+
}
83+
84+
pub struct Thing {
85+
description: String,
86+
}
87+
88+
make_getter!(Thing, description, String);
89+
```
90+
91+
This expands to:
92+
93+
```rust
94+
pub struct Thing {
95+
description: String,
96+
}
97+
98+
impl Thing {
99+
pub fn get_description(&self) -> &String {
100+
&self.description
101+
}
102+
}
103+
```
104+
105+
#### Create names for macro generated tests
106+
107+
```rust
108+
#![feature(macro_metavar_expr_concat)]
109+
110+
macro_rules! test_math {
111+
($integer:ident) => {
112+
#[test]
113+
fn ${ concat(test_, $integer, _, addition) } () {
114+
let a: $integer = 73;
115+
let b: $integer = 42;
116+
assert_eq!(a + b, 115)
117+
}
118+
119+
#[test]
120+
fn ${ concat(test_, $integer, _, subtraction) } () {
121+
let a: $integer = 73;
122+
let b: $integer = 42;
123+
assert_eq!(a - b, 31)
124+
}
125+
}
126+
}
127+
128+
test_math!(i32);
129+
test_math!(u64);
130+
test_math!(u128);
131+
```
132+
133+
Running this returns the following output:
134+
135+
```text
136+
running 6 tests
137+
test test_i32_subtraction ... ok
138+
test test_i32_addition ... ok
139+
test test_u128_addition ... ok
140+
test test_u128_subtraction ... ok
141+
test test_u64_addition ... ok
142+
test test_u64_subtraction ... ok
143+
144+
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
145+
```
146+
147+
[^1]: An alternative is the [`paste`] crate.
148+
149+
[`paste`]: https://crates.io/crates/paste
150+
[RFC 3086]: https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html
151+
[`concat_idents!`]: https://doc.rust-lang.org/nightly/std/macro.concat_idents.html
152+
[`macro_metavar_expr`]: ./macro-metavar-expr.md
153+
[`concat_ident`]: ./concat-ident.md
154+
[#124225]: https://github.com/rust-lang/rust/issues/124225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# `macro_metavar_expr`
2+
3+
The tracking issue for this feature is: [#83527]
4+
5+
------------------------
6+
7+
> This feature is not to be confused with [`macro_metavar_expr_concat`].
8+
9+
[`macro_metavar_expr_concat`]: ./macro-metavar-expr-concat.md
10+
[#83527]: https://github.com/rust-lang/rust/issues/83527

src/doc/unstable-book/src/library-features/concat-idents.md

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ The tracking issue for this feature is: [#29599]
66

77
------------------------
88

9+
> This feature is expected to be removed in favor of [`macro_metavar_expr_concat`](./macro-metavar-expr-concat.md).
10+
911
The `concat_idents` feature adds a macro for concatenating multiple identifiers
1012
into one identifier.
1113

0 commit comments

Comments
 (0)