7
7
//LICENSE All rights reserved.
8
8
//LICENSE
9
9
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
10
- use bindgen:: callbacks:: { DeriveTrait , ImplementsTrait , MacroParsingBehavior } ;
10
+ use bindgen:: callbacks:: { DeriveTrait , EnumVariantValue , ImplementsTrait , MacroParsingBehavior } ;
11
11
use bindgen:: NonCopyUnionStyle ;
12
12
use eyre:: { eyre, WrapErr } ;
13
13
use pgrx_pg_config:: {
14
14
is_supported_major_version, prefix_path, PgConfig , PgConfigSelector , Pgrx , SUPPORTED_VERSIONS ,
15
15
} ;
16
16
use quote:: { quote, ToTokens } ;
17
+ use std:: cell:: RefCell ;
17
18
use std:: cmp:: Ordering ;
18
19
use std:: collections:: { BTreeMap , BTreeSet , HashMap , HashSet } ;
19
20
use std:: fs;
20
21
use std:: path:: { self , Path , PathBuf } ; // disambiguate path::Path and syn::Type::Path
21
22
use std:: process:: { Command , Output } ;
23
+ use std:: rc:: Rc ;
22
24
use std:: sync:: OnceLock ;
23
25
use syn:: { ForeignItem , Item , ItemConst } ;
24
26
@@ -30,44 +32,49 @@ mod build {
30
32
}
31
33
32
34
#[ derive( Debug ) ]
33
- struct PgrxOverrides ( HashSet < String > ) ;
35
+ struct BindingOverride {
36
+ ignore_macros : HashSet < & ' static str > ,
37
+ enum_names : InnerMut < EnumMap > ,
38
+ }
39
+
40
+ type InnerMut < T > = Rc < RefCell < T > > ;
41
+ type EnumMap = BTreeMap < String , Vec < ( String , EnumVariantValue ) > > ;
34
42
35
- impl PgrxOverrides {
36
- fn default ( ) -> Self {
43
+ impl BindingOverride {
44
+ fn new_from ( enum_names : InnerMut < EnumMap > ) -> Self {
37
45
// these cause duplicate definition problems on linux
38
46
// see: https://github.com/rust-lang/rust-bindgen/issues/687
39
- PgrxOverrides (
40
- vec ! [
41
- "FP_INFINITE" . into ( ) ,
42
- "FP_NAN" . into ( ) ,
43
- "FP_NORMAL" . into ( ) ,
44
- "FP_SUBNORMAL" . into ( ) ,
45
- "FP_ZERO" . into ( ) ,
46
- "IPPORT_RESERVED" . into ( ) ,
47
+ BindingOverride {
48
+ ignore_macros : HashSet :: from_iter ( [
49
+ "FP_INFINITE" ,
50
+ "FP_NAN" ,
51
+ "FP_NORMAL" ,
52
+ "FP_SUBNORMAL" ,
53
+ "FP_ZERO" ,
54
+ "IPPORT_RESERVED" ,
47
55
// These are just annoying due to clippy
48
- "M_E" . into( ) ,
49
- "M_LOG2E" . into( ) ,
50
- "M_LOG10E" . into( ) ,
51
- "M_LN2" . into( ) ,
52
- "M_LN10" . into( ) ,
53
- "M_PI" . into( ) ,
54
- "M_PI_2" . into( ) ,
55
- "M_PI_4" . into( ) ,
56
- "M_1_PI" . into( ) ,
57
- "M_2_PI" . into( ) ,
58
- "M_SQRT2" . into( ) ,
59
- "M_SQRT1_2" . into( ) ,
60
- "M_2_SQRTPI" . into( ) ,
61
- ]
62
- . into_iter ( )
63
- . collect ( ) ,
64
- )
56
+ "M_E" ,
57
+ "M_LOG2E" ,
58
+ "M_LOG10E" ,
59
+ "M_LN2" ,
60
+ "M_LN10" ,
61
+ "M_PI" ,
62
+ "M_PI_2" ,
63
+ "M_PI_4" ,
64
+ "M_1_PI" ,
65
+ "M_2_PI" ,
66
+ "M_SQRT2" ,
67
+ "M_SQRT1_2" ,
68
+ "M_2_SQRTPI" ,
69
+ ] ) ,
70
+ enum_names,
71
+ }
65
72
}
66
73
}
67
74
68
- impl bindgen:: callbacks:: ParseCallbacks for PgrxOverrides {
75
+ impl bindgen:: callbacks:: ParseCallbacks for BindingOverride {
69
76
fn will_parse_macro ( & self , name : & str ) -> MacroParsingBehavior {
70
- if self . 0 . contains ( name) {
77
+ if self . ignore_macros . contains ( name) {
71
78
bindgen:: callbacks:: MacroParsingBehavior :: Ignore
72
79
} else {
73
80
bindgen:: callbacks:: MacroParsingBehavior :: Default
@@ -90,6 +97,45 @@ impl bindgen::callbacks::ParseCallbacks for PgrxOverrides {
90
97
} ;
91
98
Some ( implements_trait)
92
99
}
100
+
101
+ // FIXME: alter types on some int macros to the actually-used types so we can stop as-casting them
102
+ fn int_macro ( & self , _name : & str , _value : i64 ) -> Option < bindgen:: callbacks:: IntKind > {
103
+ None
104
+ }
105
+
106
+ // FIXME: implement a... C compiler?
107
+ fn func_macro ( & self , _name : & str , _value : & [ & [ u8 ] ] ) { }
108
+
109
+ /// Intentionally doesn't do anything, just updates internal state.
110
+ fn enum_variant_behavior (
111
+ & self ,
112
+ enum_name : Option < & str > ,
113
+ variant_name : & str ,
114
+ variant_value : bindgen:: callbacks:: EnumVariantValue ,
115
+ ) -> Option < bindgen:: callbacks:: EnumVariantCustomBehavior > {
116
+ enum_name. inspect ( |name| match name. strip_prefix ( "enum" ) . unwrap_or ( name) . trim ( ) {
117
+ // specifically overridden enum
118
+ "NodeTag" => return ,
119
+ name if name. contains ( "unnamed at" ) => return ,
120
+ // to prevent problems with BuiltinOid
121
+ _ if variant_name. contains ( "OID" ) => return ,
122
+ name => self
123
+ . enum_names
124
+ . borrow_mut ( )
125
+ . entry ( name. to_string ( ) )
126
+ . or_insert ( Vec :: new ( ) )
127
+ . push ( ( variant_name. to_string ( ) , variant_value) ) ,
128
+ } ) ;
129
+ None
130
+ }
131
+
132
+ // FIXME: hide nodetag fields and default them to appropriate values
133
+ fn field_visibility (
134
+ & self ,
135
+ _info : bindgen:: callbacks:: FieldInfo < ' _ > ,
136
+ ) -> Option < bindgen:: FieldVisibilityKind > {
137
+ None
138
+ }
93
139
}
94
140
95
141
fn main ( ) -> eyre:: Result < ( ) > {
@@ -718,12 +764,15 @@ fn run_bindgen(
718
764
let builtin_includes = includes. iter ( ) . filter_map ( |p| Some ( format ! ( "-I{}" , p. to_str( ) ?) ) ) ;
719
765
binder = binder. clang_args ( builtin_includes) ;
720
766
} ;
767
+ let enum_names = Rc :: new ( RefCell :: new ( BTreeMap :: new ( ) ) ) ;
768
+ let overrides = BindingOverride :: new_from ( Rc :: clone ( & enum_names) ) ;
721
769
let bindings = binder
722
770
. header ( include_h. display ( ) . to_string ( ) )
723
771
. clang_args ( extra_bindgen_clang_args ( pg_config) ?)
724
772
. clang_args ( pg_target_include_flags ( major_version, pg_config) ?)
725
773
. detect_include_paths ( autodetect)
726
- . parse_callbacks ( Box :: new ( PgrxOverrides :: default ( ) ) )
774
+ . parse_callbacks ( Box :: new ( overrides) )
775
+ . default_enum_style ( bindgen:: EnumVariation :: ModuleConsts )
727
776
// The NodeTag enum is closed: additions break existing values in the set, so it is not extensible
728
777
. rustified_non_exhaustive_enum ( "NodeTag" )
729
778
. size_t_is_usize ( true )
@@ -733,8 +782,33 @@ fn run_bindgen(
733
782
. default_non_copy_union_style ( NonCopyUnionStyle :: ManuallyDrop )
734
783
. generate ( )
735
784
. wrap_err_with ( || format ! ( "Unable to generate bindings for pg{major_version}" ) ) ?;
785
+ let mut binding_str = bindings. to_string ( ) ;
786
+ drop ( bindings) ; // So the Rc::into_inner can unwrap
787
+
788
+ // FIXME: do this for the Node graph instead of reparsing?
789
+ let enum_names: EnumMap = Rc :: into_inner ( enum_names) . unwrap ( ) . into_inner ( ) ;
790
+ binding_str. extend ( enum_names. into_iter ( ) . flat_map ( |( name, variants) | {
791
+ const MIN_I32 : i64 = i32:: MIN as _ ;
792
+ const MAX_I32 : i64 = i32:: MAX as _ ;
793
+ const MAX_U32 : u64 = u32:: MAX as _ ;
794
+ variants. into_iter ( ) . map ( move |( variant, value) | {
795
+ let ( ty, value) = match value {
796
+ EnumVariantValue :: Boolean ( b) => ( "bool" , b. to_string ( ) ) ,
797
+ EnumVariantValue :: Signed ( v @ MIN_I32 ..=MAX_I32 ) => ( "i32" , v. to_string ( ) ) ,
798
+ EnumVariantValue :: Signed ( v) => ( "i64" , v. to_string ( ) ) ,
799
+ EnumVariantValue :: Unsigned ( v @ 0 ..=MAX_U32 ) => ( "u32" , v. to_string ( ) ) ,
800
+ EnumVariantValue :: Unsigned ( v) => ( "u64" , v. to_string ( ) ) ,
801
+ } ;
802
+ format ! (
803
+ r#"
804
+ #[deprecated(since = "0.12.0", note = "you want pg_sys::{module}::{variant}")]
805
+ pub const {module}_{variant}: {ty} = {value};"# ,
806
+ module = & * name, // imprecise closure capture
807
+ )
808
+ } )
809
+ } ) ) ;
736
810
737
- Ok ( bindings . to_string ( ) )
811
+ Ok ( binding_str )
738
812
}
739
813
740
814
fn add_blocklists ( bind : bindgen:: Builder ) -> bindgen:: Builder {
0 commit comments