@@ -6,10 +6,12 @@ use bindgen::{
6
6
} ;
7
7
use clap:: error:: { Error , ErrorKind } ;
8
8
use clap:: { CommandFactory , Parser } ;
9
+ use proc_macro2:: TokenStream ;
9
10
use std:: fs:: File ;
10
11
use std:: io;
11
12
use std:: path:: { Path , PathBuf } ;
12
13
use std:: process:: exit;
14
+ use std:: str:: FromStr ;
13
15
14
16
fn rust_target_help ( ) -> String {
15
17
format ! (
@@ -87,6 +89,43 @@ fn parse_custom_derive(
87
89
Ok ( ( derives, regex. to_owned ( ) ) )
88
90
}
89
91
92
+ fn parse_custom_attribute (
93
+ custom_attribute : & str ,
94
+ ) -> Result < ( Vec < String > , String ) , Error > {
95
+ let mut brace_level = 0 ;
96
+ let ( regex, attributes) = custom_attribute
97
+ . rsplit_once ( |c| {
98
+ match c {
99
+ ']' => brace_level += 1 ,
100
+ '[' => brace_level -= 1 ,
101
+ _ => { }
102
+ }
103
+ c == '=' && brace_level == 0
104
+ } )
105
+ . ok_or_else ( || Error :: raw ( ErrorKind :: InvalidValue , "Missing `=`" ) ) ?;
106
+
107
+ let mut brace_level = 0 ;
108
+ let attributes = attributes
109
+ . split ( |c| {
110
+ match c {
111
+ ']' => brace_level += 1 ,
112
+ '[' => brace_level -= 1 ,
113
+ _ => { }
114
+ }
115
+ c == ',' && brace_level == 0
116
+ } )
117
+ . map ( |s| s. to_owned ( ) )
118
+ . collect :: < Vec < _ > > ( ) ;
119
+
120
+ for attribute in & attributes {
121
+ if let Err ( err) = TokenStream :: from_str ( attribute) {
122
+ return Err ( Error :: raw ( ErrorKind :: InvalidValue , err) ) ;
123
+ }
124
+ }
125
+
126
+ Ok ( ( attributes, regex. to_owned ( ) ) )
127
+ }
128
+
90
129
#[ derive( Parser , Debug ) ]
91
130
#[ clap(
92
131
about = "Generates Rust bindings from C/C++ headers." ,
@@ -424,6 +463,18 @@ struct BindgenCommand {
424
463
/// Derive custom traits on a `union`. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a coma-separated list of derive macros.
425
464
#[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_derive) ]
426
465
with_derive_custom_union : Vec < ( Vec < String > , String ) > ,
466
+ /// Add custom attributes on any kind of type. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes.
467
+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_attribute) ]
468
+ with_attribute_custom : Vec < ( Vec < String > , String ) > ,
469
+ /// Add custom attributes on a `struct`. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes.
470
+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_attribute) ]
471
+ with_attribute_custom_struct : Vec < ( Vec < String > , String ) > ,
472
+ /// Add custom attributes on an `enum. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes.
473
+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_attribute) ]
474
+ with_attribute_custom_enum : Vec < ( Vec < String > , String ) > ,
475
+ /// Add custom attributes on a `union`. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes.
476
+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_attribute) ]
477
+ with_attribute_custom_union : Vec < ( Vec < String > , String ) > ,
427
478
/// Generate wrappers for `static` and `static inline` functions.
428
479
#[ arg( long, requires = "experimental" ) ]
429
480
wrap_static_fns : bool ,
@@ -574,6 +625,10 @@ where
574
625
with_derive_custom_struct,
575
626
with_derive_custom_enum,
576
627
with_derive_custom_union,
628
+ with_attribute_custom,
629
+ with_attribute_custom_struct,
630
+ with_attribute_custom_enum,
631
+ with_attribute_custom_union,
577
632
wrap_static_fns,
578
633
wrap_static_fns_path,
579
634
wrap_static_fns_suffix,
@@ -1130,6 +1185,82 @@ where
1130
1185
}
1131
1186
}
1132
1187
1188
+ #[ derive( Debug ) ]
1189
+ struct CustomAttributeCallback {
1190
+ attributes : Vec < String > ,
1191
+ kind : Option < TypeKind > ,
1192
+ regex_set : bindgen:: RegexSet ,
1193
+ }
1194
+
1195
+ impl bindgen:: callbacks:: ParseCallbacks for CustomAttributeCallback {
1196
+ fn cli_args ( & self ) -> Vec < String > {
1197
+ let mut args = vec ! [ ] ;
1198
+
1199
+ let flag = match & self . kind {
1200
+ None => "--with-attribute-custom" ,
1201
+ Some ( TypeKind :: Struct ) => "--with-attribute-custom-struct" ,
1202
+ Some ( TypeKind :: Enum ) => "--with-attribute-custom-enum" ,
1203
+ Some ( TypeKind :: Union ) => "--with-attribute-custom-union" ,
1204
+ } ;
1205
+
1206
+ let attributes = self . attributes . join ( "," ) ;
1207
+
1208
+ for item in self . regex_set . get_items ( ) {
1209
+ args. extend_from_slice ( & [
1210
+ flag. to_owned ( ) ,
1211
+ format ! ( "{}={}" , item, attributes) ,
1212
+ ] ) ;
1213
+ }
1214
+
1215
+ args
1216
+ }
1217
+
1218
+ fn add_attributes (
1219
+ & self ,
1220
+ info : & bindgen:: callbacks:: AttributeInfo < ' _ > ,
1221
+ ) -> Vec < String > {
1222
+ if self . kind . map ( |kind| kind == info. kind ) . unwrap_or ( true ) &&
1223
+ self . regex_set . matches ( info. name )
1224
+ {
1225
+ return self . attributes . clone ( ) ;
1226
+ }
1227
+ vec ! [ ]
1228
+ }
1229
+ }
1230
+
1231
+ for ( custom_attributes, kind, name) in [
1232
+ ( with_attribute_custom, None , "--with-attribute-custom" ) ,
1233
+ (
1234
+ with_attribute_custom_struct,
1235
+ Some ( TypeKind :: Struct ) ,
1236
+ "--with-attribute-custom-struct" ,
1237
+ ) ,
1238
+ (
1239
+ with_attribute_custom_enum,
1240
+ Some ( TypeKind :: Enum ) ,
1241
+ "--with-attribute-custom-enum" ,
1242
+ ) ,
1243
+ (
1244
+ with_attribute_custom_union,
1245
+ Some ( TypeKind :: Union ) ,
1246
+ "--with-attribute-custom-union" ,
1247
+ ) ,
1248
+ ] {
1249
+ let name = emit_diagnostics. then_some ( name) ;
1250
+ for ( attributes, regex) in custom_attributes {
1251
+ let mut regex_set = RegexSet :: new ( ) ;
1252
+ regex_set. insert ( regex) ;
1253
+ regex_set. build_with_diagnostics ( false , name) ;
1254
+
1255
+ builder =
1256
+ builder. parse_callbacks ( Box :: new ( CustomAttributeCallback {
1257
+ attributes,
1258
+ kind,
1259
+ regex_set,
1260
+ } ) ) ;
1261
+ }
1262
+ }
1263
+
1133
1264
if wrap_static_fns {
1134
1265
builder = builder. wrap_static_fns ( true ) ;
1135
1266
}
0 commit comments