@@ -90,35 +90,49 @@ For example, let's make a simplified (and slightly contrived) version of the `lo
90
90
edition style:
91
91
92
92
``` rust,ignore
93
+ /// How important/severe the log message is.
94
+ #[derive(Copy, Clone)]
93
95
pub struct LogLevel {
94
96
Warn,
95
97
Error
96
98
}
97
99
100
+ impl fmt::Display for LogLevel {
101
+ pub fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102
+ match self {
103
+ LogLevel::Warn => write!(f, "warning"),
104
+ LogLevel::Error => write!(f, "error"),
105
+ }
106
+ }
107
+ }
108
+
109
+ // A helper macro to log the message.
98
110
#[doc(hidden)]
99
111
#[macro_export]
100
- macro_rules! log {
101
- ($level:expr, $msg:expr) => {
112
+ macro_rules! __impl_log {
113
+ ($level:expr, $msg:expr) => {{
102
114
println!("{}: {}", $level, $msg)
103
- }
115
+ }}
104
116
}
105
117
118
+ /// Warn level log message
106
119
#[macro_export]
107
120
macro_rules! warn {
108
- ($msg:expr ) => {
109
- log!(stringify!( $crate::LogLevel::Warn), $msg )
121
+ ($($args:tt)* ) => {
122
+ __impl_log!( $crate::LogLevel::Warn, format_args!($($args)*) )
110
123
}
111
124
}
112
125
126
+ /// Error level log message
113
127
#[macro_export]
114
128
macro_rules! error {
115
- ($msg:expr ) => {
116
- log!(stringify!( $crate::LogLevel::Error), $msg )
129
+ ($($args:tt)* ) => {
130
+ __impl_log!( $crate::LogLevel::Error, format_args!($($args)*) )
117
131
}
118
132
}
119
133
```
120
134
121
- Our ` log !` macro is private to our module, but needs to be exported as it is called by other
135
+ Our ` __impl_log !` macro is private to our module, but needs to be exported as it is called by other
122
136
macros, and in 2015 edition all used macros must be exported.
123
137
124
138
Now, in 2018 this example will not compile:
@@ -131,14 +145,14 @@ fn main() {
131
145
}
132
146
```
133
147
134
- will give an error message about not finding the ` log !` macro. This is because unlike in the 2015
135
- edition, macros are namespaced and we must import them. We could do
148
+ will give an error message about not finding the ` __impl_log !` macro. This is because unlike in
149
+ the 2015 edition, macros are namespaced and we must import them. We could do
136
150
137
151
``` rust,ignore
138
- use log::{log , error};
152
+ use log::{__impl_log , error};
139
153
```
140
154
141
- which would make our code compile, but ` log ` is meant to be an implementation detail!
155
+ which would make our code compile, but ` __impl_log ` is meant to be an implementation detail!
142
156
143
157
#### Macros with ` $crate:: ` prefix.
144
158
@@ -147,8 +161,8 @@ you would for any other path. Versions of the compiler >= 1.30 will handle this
147
161
148
162
``` rust,ignore
149
163
macro_rules! warn {
150
- ($msg:expr ) => {
151
- $crate::log!(stringify!( $crate::LogLevel::Warn), $msg )
164
+ ($($args:tt)* ) => {
165
+ $crate::__impl_log!( $crate::LogLevel::Warn, format_args!($($args)*) )
152
166
}
153
167
}
154
168
@@ -167,24 +181,26 @@ modifier). The downside is that it's a bit messier:
167
181
``` rust,ignore
168
182
#[macro_export(local_inner_macros)]
169
183
macro_rules! warn {
170
- ($msg:expr ) => {
171
- log!(stringify!( $crate::LogLevel::Warn), $msg )
184
+ ($($args:tt)* ) => {
185
+ __impl_log!( $crate::LogLevel::Warn, format_args!($($args)*) )
172
186
}
173
187
}
174
188
```
175
189
176
190
So the code knows to look for any macros used locally. But wait - this won't compile, because we
177
- use the ` stringify !` macro that isn't in our local crate (hence the convoluted example). The
178
- solution is to add a level of indirection: we crate a macro that wraps stringify , but is local to
179
- our crate. That way everything works in both editions (sadly we have to pollute the global
191
+ use the ` format_args !` macro that isn't in our local crate (hence the convoluted example). The
192
+ solution is to add a level of indirection: we crate a macro that wraps ` format_args ` , but is local
193
+ to our crate. That way everything works in both editions (sadly we have to pollute the global
180
194
namespace a bit, but that's ok).
181
195
182
196
``` rust,ignore
197
+ // I've used the pattern `_<my crate name>__<macro name>` to name this macro, hopefully avoiding
198
+ // name clashes.
183
199
#[doc(hidden)]
184
200
#[macro_export]
185
- macro_rules! my_special_stringify {
201
+ macro_rules! _log__format_args {
186
202
($($inner:tt)*) => {
187
- stringify!( $($inner)*)
203
+ format_args! { $($inner)* }
188
204
}
189
205
}
190
206
```
@@ -194,39 +210,53 @@ whatever tokens we get to the inner macro, and rely on it to report errors.
194
210
195
211
So the full 2015/2018 working example would be:
196
212
197
- ``` rust,ignore
213
+ ``` rust
214
+ /// How important/severe the log message is.
215
+ #[derive(Copy , Clone )]
198
216
pub struct LogLevel {
199
217
Warn ,
200
218
Error
201
219
}
202
220
221
+ impl fmt :: Display for LogLevel {
222
+ pub fn fmt (& self , f : & mut fmt :: Formatter ) -> fmt :: Result {
223
+ match self {
224
+ LogLevel :: Warn => write! (f , " warning" ),
225
+ LogLevel :: Error => write! (f , " error" ),
226
+ }
227
+ }
228
+ }
229
+
230
+ // A helper macro to log the message.
203
231
#[doc(hidden)]
204
232
#[macro_export]
205
- macro_rules! log {
206
- ($level:expr, $msg:expr) => {
233
+ macro_rules! __impl_log {
234
+ ($ level : expr , $ msg : expr ) => {{
207
235
println! (" {}: {}" , $ level , $ msg )
208
- }
236
+ }}
209
237
}
210
238
239
+ /// Warn level log message
211
240
#[macro_export(local_inner_macros)]
212
241
macro_rules! warn {
213
- ($msg:expr ) => {
214
- log!(my_special_stringify!( $crate::LogLevel::Warn), $msg )
242
+ ($ ( $ args : tt ) * ) => {
243
+ __impl_log! ( $ crate :: LogLevel :: Warn , format_args! ( $ ( $ args ) * ) )
215
244
}
216
245
}
217
246
247
+ /// Error level log message
218
248
#[macro_export(local_inner_macros)]
219
249
macro_rules! error {
220
- ($msg:expr ) => {
221
- log!(my_special_stringify!( $crate::LogLevel::Error), $msg )
250
+ ($ ( $ args : tt ) * ) => {
251
+ __impl_log! ( $ crate :: LogLevel :: Error , format_args! ( $ ( $ args ) * ) )
222
252
}
223
253
}
224
254
225
255
#[doc(hidden)]
226
256
#[macro_export]
227
- macro_rules! my_special_stringify {
228
- ($($args :tt)*) => {
229
- stringify!( $($args)*)
257
+ macro_rules! _log__format_args {
258
+ ($ ($ inner : tt )* ) => {
259
+ format_args! { $ ($ inner ) * }
230
260
}
231
261
}
232
262
```
0 commit comments