1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//! ## HexGa Map On
//!
//! The core `map_on!` macro allows you to iterate over a list of tokens and generate repetitive code patterns.
//! This is particularly useful for avoiding repetitive boilerplate code when implementing traits for multiple primitive types for example.
//!
//! The fundamental idea is simple: take a list of tokens and apply a macro to each one.
//! This is useful for avoiding boilerplate when implementing traits for multiple types:
//!
//! ```rust
//! use hexga_map_on::*;
//!
//! trait MinusOne
//! {
//! const MINUS_ONE : Self;
//! }
//!
//! map_on!
//! (
//! (
//! i8, i16, i32, i64, isize,
//! f32, f64
//! ),
//! ($name:ident) =>
//! {
//! impl MinusOne for $name
//! {
//! const MINUS_ONE : Self = -1 as Self;
//! }
//! }
//! );
//! ```
//!
//! Some variation of `map_on` exist for different use case :
//!
//! ```rust
//! use hexga_map_on::*;
//!
//! trait Zero
//! {
//! const ZERO : Self;
//! }
//!
//! map_on_number!(
//! ($name:ident) =>
//! {
//! impl Zero for $name
//! {
//! const ZERO : Self = 0 as Self;
//! }
//! }
//! );
//! ```
//!
//! ## More Example
//!
//! You can also use the `map_on!` macro to call another macro :
//!
//! ```rust
//! use hexga_map_on::*;
//!
//! trait One
//! {
//! const ONE : Self;
//! }
//!
//! macro_rules! impl_one {
//! ($type_name:ty) => {
//! impl One for $type_name
//! {
//! const ONE : Self = 1 as Self;
//! }
//! };
//! }
//!
//! map_on_number!(impl_one);
//! ```
//!
//! It is also possible to use nested `map_on!`*1 macro (only when using macro name, or in const context like implementing a trait) :
//!
//! ```rust
//! use hexga_map_on::*;
//!
//! pub trait CastInto<T>
//! {
//! /// Might lose some precision.
//! /// Same semantics as the [as](https://practice.course.rs/type-conversions/as.html) keyword: `4f32 as u64`
//! fn cast_into(self) -> T;
//! }
//!
//! // Double recursive macro :)
//! macro_rules! impl_cast_into
//! {
//! ($itself: ty, $cast_into: ty) =>
//! {
//! impl CastInto<$cast_into> for $itself
//! {
//! fn cast_into(self) -> $cast_into { self as _ }
//! }
//! };
//!
//! ($cast_into: ty) =>
//! {
//! map_on_number!(impl_cast_into,$cast_into);
//! };
//! }
//! // Do 144 trait impl in a few lines :)
//! map_on_number!(impl_cast_into);
//!
//! fn main()
//! {
//! assert_eq!(20.5f32 as i8, 20.5f32.cast_into());
//! assert_eq!(4.5 as u32, 4.5.cast_into());
//! assert_eq!(4u8 as i64, 4u8.cast_into());
//! }
//! ```
//!
//! Implementing a binary operator is also possible :
//!
//! ```rust
//! use hexga_map_on::*;
//!
//! #[derive(Debug)]
//! struct X(pub i32);
//!
//! map_on_operator_binary!(
//! (($trait_name: tt, $fn_name: tt)) =>
//! {
//! impl std::ops::$trait_name for X
//! {
//! type Output = X;
//! fn $fn_name(self, rhs : Self) -> Self::Output { X(self.0.$fn_name(rhs.0)) }
//! }
//! }
//! );
//!
//! fn main()
//! {
//! let x = X(9) + X(3) * X(4) / X(2);
//! assert_eq!(x.0, 9 + 3 * 4 / 2 );
//! }
//! ```
//!
//! Check the `example` folder for more examples.
//!
//! ## Limitation
//!
//! Right now it is impossible to use the `map_on!` macro in a non const context (like in a function body) with lambda syntax.
//!
//! ```rust,ignore
//! use hexga_map_on::map_on;
//!
//! macro_rules! print_type {
//! ($type_name:ty) => {
//! println!("print type from macro name {}", ::std::any::type_name::<$type_name>());
//! };
//! }
//!
//! fn main()
//! {
//! // work fine
//! map_on!((f32, f64), print_type);
//!
//! // Don't work :/
//! map_on!((f32, f64),
//! ($type_name:ident) =>
//! {
//! println!("print type from macro lambda {}", ::std::any::type_name::<$type_name>());
//! }
//! );
//! }
//! ```
//!
//! The reason is that the lambda macro form will create a temporary macro with the name `__map_on_inliner`.
//! Because nested lambda map_on! macro call will generate a new macro each time with the same name `__map_on_inliner`, it will conflict with the previous one.
//! So we need a mecansime to scope the macro name.
//!
//! Right now the only way to do that that I know is to use a `const` block, which is not ideal because it limit where the macro can be used : in a const context.
//!
//! ```rust
//! const _: () = {
//! // definitions, trait impls, etc…
//! };
//! ```
//! <https://internals.rust-lang.org/t/anonymous-modules/15441/2?u=thomas-mewily>
//!
//! The definiton for lambda `map_on!` macro is the following :
//!
//! ```rust,ignore
//! ($tokens:tt, $($macro_arms:tt)+) => {
//! const _: () = {
//! macro_rules! __map_on_inliner {
//! $($macro_arms)+
//! }
//!
//! $crate::map_on!(@expand_tokens $tokens);
//! };
//! };
//! ```
//!
//! This is the kind of stuff I was doing in C, ported to Rust while also using the full power of Rust macros.
//!
//! The official name for this technique seem to be `X macro`, but since the main focus is mapping tokens over tokens I prefer the name `map_on macro`.
//! https://en.wikipedia.org/wiki/X_macro
//!