@@ -6,10 +6,12 @@ use bindgen::{
66} ;
77use clap:: error:: { Error , ErrorKind } ;
88use clap:: { CommandFactory , Parser } ;
9+ use proc_macro2:: TokenStream ;
910use std:: fs:: File ;
1011use std:: io;
1112use std:: path:: { Path , PathBuf } ;
1213use std:: process:: exit;
14+ use std:: str:: FromStr ;
1315
1416fn rust_target_help ( ) -> String {
1517 format ! (
@@ -87,6 +89,43 @@ fn parse_custom_derive(
8789 Ok ( ( derives, regex. to_owned ( ) ) )
8890}
8991
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+
90129#[ derive( Parser , Debug ) ]
91130#[ clap(
92131 about = "Generates Rust bindings from C/C++ headers." ,
@@ -424,6 +463,18 @@ struct BindgenCommand {
424463 /// 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.
425464 #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_derive) ]
426465 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 ) > ,
427478 /// Generate wrappers for `static` and `static inline` functions.
428479 #[ arg( long, requires = "experimental" ) ]
429480 wrap_static_fns : bool ,
@@ -574,6 +625,10 @@ where
574625 with_derive_custom_struct,
575626 with_derive_custom_enum,
576627 with_derive_custom_union,
628+ with_attribute_custom,
629+ with_attribute_custom_struct,
630+ with_attribute_custom_enum,
631+ with_attribute_custom_union,
577632 wrap_static_fns,
578633 wrap_static_fns_path,
579634 wrap_static_fns_suffix,
@@ -1130,6 +1185,82 @@ where
11301185 }
11311186 }
11321187
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+
11331264 if wrap_static_fns {
11341265 builder = builder. wrap_static_fns ( true ) ;
11351266 }
0 commit comments