@@ -2,8 +2,8 @@ use once_cell::sync::Lazy;
2
2
use quote:: { quote, ToTokens } ;
3
3
use regex:: Regex ;
4
4
use syn:: {
5
- punctuated:: Punctuated , Attribute , Data , DeriveInput , Error , Expr , Lit , LitBool , LitStr ,
6
- MetaNameValue , Result , Token ,
5
+ punctuated:: Punctuated , Attribute , Data , DeriveInput , Error , Expr , Field , Lit , LitBool , LitStr ,
6
+ Meta , MetaNameValue , Result , Token ,
7
7
} ;
8
8
9
9
use crate :: { metric:: Metric , with_attrs:: WithAttrs } ;
@@ -17,6 +17,19 @@ static METRIC_NAME_RE: Lazy<Regex> =
17
17
/// Supported metrics separators
18
18
const SUPPORTED_SEPARATORS : & [ & str ] = & [ "." , "_" , ":" ] ;
19
19
20
+ enum MetricField < ' a > {
21
+ Included ( Metric < ' a > ) ,
22
+ Skipped ( & ' a Field ) ,
23
+ }
24
+
25
+ impl < ' a > MetricField < ' a > {
26
+ fn field ( & self ) -> & ' a Field {
27
+ match self {
28
+ MetricField :: Included ( Metric { field, .. } ) | MetricField :: Skipped ( field) => field,
29
+ }
30
+ }
31
+ }
32
+
20
33
pub ( crate ) fn derive ( node : & DeriveInput ) -> Result < proc_macro2:: TokenStream > {
21
34
let ty = & node. ident ;
22
35
let vis = & node. vis ;
@@ -36,30 +49,49 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
36
49
let ( defaults, labeled_defaults, describes) : ( Vec < _ > , Vec < _ > , Vec < _ > ) = metric_fields
37
50
. iter ( )
38
51
. map ( |metric| {
39
- let field_name = & metric. field . ident ;
40
- let metric_name =
41
- format ! ( "{}{}{}" , scope. value( ) , metrics_attr. separator( ) , metric. name( ) ) ;
42
- let registrar = metric. register_stmt ( ) ?;
43
- let describe = metric. describe_stmt ( ) ?;
44
- let description = & metric. description ;
45
- Ok ( (
46
- quote ! {
47
- #field_name: #registrar( #metric_name) ,
48
- } ,
49
- quote ! {
50
- #field_name: #registrar( #metric_name, labels. clone( ) ) ,
51
- } ,
52
- quote ! {
53
- #describe( #metric_name, #description) ;
54
- } ,
55
- ) )
52
+ let field_name = & metric. field ( ) . ident ;
53
+ match metric {
54
+ MetricField :: Included ( metric) => {
55
+ let metric_name = format ! (
56
+ "{}{}{}" ,
57
+ scope. value( ) ,
58
+ metrics_attr. separator( ) ,
59
+ metric. name( )
60
+ ) ;
61
+ let registrar = metric. register_stmt ( ) ?;
62
+ let describe = metric. describe_stmt ( ) ?;
63
+ let description = & metric. description ;
64
+ Ok ( (
65
+ quote ! {
66
+ #field_name: #registrar( #metric_name) ,
67
+ } ,
68
+ quote ! {
69
+ #field_name: #registrar( #metric_name, labels. clone( ) ) ,
70
+ } ,
71
+ Some ( quote ! {
72
+ #describe( #metric_name, #description) ;
73
+ } ) ,
74
+ ) )
75
+ }
76
+ MetricField :: Skipped ( _) => Ok ( (
77
+ quote ! {
78
+ #field_name: Default :: default ( ) ,
79
+ } ,
80
+ quote ! {
81
+ #field_name: Default :: default ( ) ,
82
+ } ,
83
+ None ,
84
+ ) ) ,
85
+ }
56
86
} )
57
87
. collect :: < Result < Vec < _ > > > ( ) ?
58
88
. into_iter ( )
59
89
. fold ( ( vec ! [ ] , vec ! [ ] , vec ! [ ] ) , |mut acc, x| {
60
90
acc. 0 . push ( x. 0 ) ;
61
91
acc. 1 . push ( x. 1 ) ;
62
- acc. 2 . push ( x. 2 ) ;
92
+ if let Some ( describe) = x. 2 {
93
+ acc. 2 . push ( describe) ;
94
+ }
63
95
acc
64
96
} ) ;
65
97
@@ -93,35 +125,50 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
93
125
let ( defaults, labeled_defaults, describes) : ( Vec < _ > , Vec < _ > , Vec < _ > ) = metric_fields
94
126
. iter ( )
95
127
. map ( |metric| {
96
- let name = metric. name ( ) ;
97
- let separator = metrics_attr. separator ( ) ;
98
- let metric_name = quote ! {
99
- format!( "{}{}{}" , scope, #separator, #name)
100
- } ;
101
- let field_name = & metric. field . ident ;
102
-
103
- let registrar = metric. register_stmt ( ) ?;
104
- let describe = metric. describe_stmt ( ) ?;
105
- let description = & metric. description ;
106
-
107
- Ok ( (
108
- quote ! {
109
- #field_name: #registrar( #metric_name) ,
110
- } ,
111
- quote ! {
112
- #field_name: #registrar( #metric_name, labels. clone( ) ) ,
113
- } ,
114
- quote ! {
115
- #describe( #metric_name, #description) ;
116
- } ,
117
- ) )
128
+ let field_name = & metric. field ( ) . ident ;
129
+ match metric {
130
+ MetricField :: Included ( metric) => {
131
+ let name = metric. name ( ) ;
132
+ let separator = metrics_attr. separator ( ) ;
133
+ let metric_name = quote ! {
134
+ format!( "{}{}{}" , scope, #separator, #name)
135
+ } ;
136
+
137
+ let registrar = metric. register_stmt ( ) ?;
138
+ let describe = metric. describe_stmt ( ) ?;
139
+ let description = & metric. description ;
140
+
141
+ Ok ( (
142
+ quote ! {
143
+ #field_name: #registrar( #metric_name) ,
144
+ } ,
145
+ quote ! {
146
+ #field_name: #registrar( #metric_name, labels. clone( ) ) ,
147
+ } ,
148
+ Some ( quote ! {
149
+ #describe( #metric_name, #description) ;
150
+ } ) ,
151
+ ) )
152
+ }
153
+ MetricField :: Skipped ( _) => Ok ( (
154
+ quote ! {
155
+ #field_name: Default :: default ( ) ,
156
+ } ,
157
+ quote ! {
158
+ #field_name: Default :: default ( ) ,
159
+ } ,
160
+ None ,
161
+ ) ) ,
162
+ }
118
163
} )
119
164
. collect :: < Result < Vec < _ > > > ( ) ?
120
165
. into_iter ( )
121
166
. fold ( ( vec ! [ ] , vec ! [ ] , vec ! [ ] ) , |mut acc, x| {
122
167
acc. 0 . push ( x. 0 ) ;
123
168
acc. 1 . push ( x. 1 ) ;
124
- acc. 2 . push ( x. 2 ) ;
169
+ if let Some ( describe) = x. 2 {
170
+ acc. 2 . push ( describe) ;
171
+ }
125
172
acc
126
173
} ) ;
127
174
@@ -246,40 +293,57 @@ fn parse_metrics_attr(node: &DeriveInput) -> Result<MetricsAttr> {
246
293
Ok ( MetricsAttr { scope, separator } )
247
294
}
248
295
249
- fn parse_metric_fields ( node : & DeriveInput ) -> Result < Vec < Metric < ' _ > > > {
296
+ fn parse_metric_fields ( node : & DeriveInput ) -> Result < Vec < MetricField < ' _ > > > {
250
297
let Data :: Struct ( ref data) = node. data else {
251
298
return Err ( Error :: new_spanned ( node, "Only structs are supported." ) )
252
299
} ;
253
300
254
301
let mut metrics = Vec :: with_capacity ( data. fields . len ( ) ) ;
255
302
for field in data. fields . iter ( ) {
256
- let ( mut describe, mut rename) = ( None , None ) ;
303
+ let ( mut describe, mut rename, mut skip ) = ( None , None , false ) ;
257
304
if let Some ( metric_attr) = parse_single_attr ( field, "metric" ) ? {
258
- let parsed = metric_attr
259
- . parse_args_with ( Punctuated :: < MetaNameValue , Token ! [ , ] > :: parse_terminated) ?;
260
- for kv in parsed {
261
- let lit = match kv. value {
262
- Expr :: Lit ( ref expr) => & expr. lit ,
263
- _ => continue ,
264
- } ;
265
- if kv. path . is_ident ( "describe" ) {
266
- if describe. is_some ( ) {
267
- return Err ( Error :: new_spanned ( kv, "Duplicate `describe` value provided." ) )
268
- }
269
- describe = Some ( parse_str_lit ( lit) ?) ;
270
- } else if kv. path . is_ident ( "rename" ) {
271
- if rename. is_some ( ) {
272
- return Err ( Error :: new_spanned ( kv, "Duplicate `rename` value provided." ) )
305
+ let parsed =
306
+ metric_attr. parse_args_with ( Punctuated :: < Meta , Token ! [ , ] > :: parse_terminated) ?;
307
+ for meta in parsed {
308
+ match meta {
309
+ Meta :: Path ( path) if path. is_ident ( "skip" ) => skip = true ,
310
+ Meta :: NameValue ( kv) => {
311
+ let lit = match kv. value {
312
+ Expr :: Lit ( ref expr) => & expr. lit ,
313
+ _ => continue ,
314
+ } ;
315
+ if kv. path . is_ident ( "describe" ) {
316
+ if describe. is_some ( ) {
317
+ return Err ( Error :: new_spanned (
318
+ kv,
319
+ "Duplicate `describe` value provided." ,
320
+ ) )
321
+ }
322
+ describe = Some ( parse_str_lit ( lit) ?) ;
323
+ } else if kv. path . is_ident ( "rename" ) {
324
+ if rename. is_some ( ) {
325
+ return Err ( Error :: new_spanned (
326
+ kv,
327
+ "Duplicate `rename` value provided." ,
328
+ ) )
329
+ }
330
+ let rename_lit = parse_str_lit ( lit) ?;
331
+ validate_metric_name ( & rename_lit) ?;
332
+ rename = Some ( rename_lit)
333
+ } else {
334
+ return Err ( Error :: new_spanned ( kv, "Unsupported attribute entry." ) )
335
+ }
273
336
}
274
- let rename_lit = parse_str_lit ( lit) ?;
275
- validate_metric_name ( & rename_lit) ?;
276
- rename = Some ( rename_lit)
277
- } else {
278
- return Err ( Error :: new_spanned ( kv, "Unsupported attribute entry." ) )
337
+ _ => return Err ( Error :: new_spanned ( meta, "Unsupported attribute entry." ) ) ,
279
338
}
280
339
}
281
340
}
282
341
342
+ if skip {
343
+ metrics. push ( MetricField :: Skipped ( field) ) ;
344
+ continue
345
+ }
346
+
283
347
let description = match describe {
284
348
Some ( lit_str) => lit_str. value ( ) ,
285
349
// Parse docs only if `describe` attribute was not provided
@@ -294,7 +358,7 @@ fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<Metric<'_>>> {
294
358
} ,
295
359
} ;
296
360
297
- metrics. push ( Metric :: new ( field, description, rename) ) ;
361
+ metrics. push ( MetricField :: Included ( Metric :: new ( field, description, rename) ) ) ;
298
362
}
299
363
300
364
Ok ( metrics)
0 commit comments