summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poveda Ruiz <31802960+pvdrz@users.noreply.github.com>2022-11-02 13:46:22 -0500
committerGitHub <noreply@github.com>2022-11-02 13:46:22 -0500
commita673a6bc9b83675a7468379e79dcf5d5659c4623 (patch)
tree5bf1b4d228bd8ff451d790c85cf4033e49cd9ff2
parent83426897af20d938fb4dca879d54de456ab96d6b (diff)
Allow callback composition (#2330)
* Allow callback composition Store all the callbacks added to the builder in a `Vec` so bindgen invokes each one of them in a last-to-first manner.
-rw-r--r--CHANGELOG.md2
-rw-r--r--bindgen/codegen/mod.rs21
-rw-r--r--bindgen/ir/context.rs39
-rw-r--r--bindgen/ir/enum_ty.rs8
-rw-r--r--bindgen/ir/function.rs9
-rw-r--r--bindgen/ir/item.rs4
-rw-r--r--bindgen/ir/var.rs10
-rw-r--r--bindgen/lib.rs26
8 files changed, 69 insertions, 50 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index de08d829..560ce38b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -154,6 +154,8 @@
* Regex inputs are sanitized so alternation (`a|b`) is handled correctly but
wildcard patterns (`*`) are now considered invalid.
* the `ParseCallbacks`trait does not require to implement `UnwindSafe`.
+ * the `Builder::parse_callbacks` method no longer overwrites previously added
+ callbacks and composes them in a last-to-first manner.
## Removed
diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs
index bf0b3356..a59265ab 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -2112,12 +2112,11 @@ impl CodeGenerator for CompInfo {
// The custom derives callback may return a list of derive attributes;
// add them to the end of the list.
- let custom_derives;
- if let Some(cb) = &ctx.options().parse_callbacks {
- custom_derives = cb.add_derives(&canonical_name);
- // In most cases this will be a no-op, since custom_derives will be empty.
- derives.extend(custom_derives.iter().map(|s| s.as_str()));
- };
+ let custom_derives = ctx
+ .options()
+ .all_callbacks(|cb| cb.add_derives(&canonical_name));
+ // In most cases this will be a no-op, since custom_derives will be empty.
+ derives.extend(custom_derives.iter().map(|s| s.as_str()));
if !derives.is_empty() {
attributes.push(attributes::derives(&derives))
@@ -3152,12 +3151,10 @@ impl CodeGenerator for Enum {
// The custom derives callback may return a list of derive attributes;
// add them to the end of the list.
- let custom_derives;
- if let Some(cb) = &ctx.options().parse_callbacks {
- custom_derives = cb.add_derives(&name);
- // In most cases this will be a no-op, since custom_derives will be empty.
- derives.extend(custom_derives.iter().map(|s| s.as_str()));
- };
+ let custom_derives =
+ ctx.options().all_callbacks(|cb| cb.add_derives(&name));
+ // In most cases this will be a no-op, since custom_derives will be empty.
+ derives.extend(custom_derives.iter().map(|s| s.as_str()));
attrs.push(attributes::derives(&derives));
}
diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs
index d987534d..928f2406 100644
--- a/bindgen/ir/context.rs
+++ b/bindgen/ir/context.rs
@@ -19,7 +19,6 @@ use super::module::{Module, ModuleKind};
use super::template::{TemplateInstantiation, TemplateParameters};
use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, Type, TypeKind};
-use crate::callbacks::ParseCallbacks;
use crate::clang::{self, Cursor};
use crate::parse::ClangItemParser;
use crate::BindgenOptions;
@@ -619,15 +618,10 @@ If you encounter an error missing from this list, please file an issue or a PR!"
)
}
- /// Get the user-provided callbacks by reference, if any.
- pub fn parse_callbacks(&self) -> Option<&dyn ParseCallbacks> {
- self.options().parse_callbacks.as_deref()
- }
-
/// Add another path to the set of included files.
pub fn include_file(&mut self, filename: String) {
- if let Some(cbs) = self.parse_callbacks() {
- cbs.include_file(&filename);
+ for cb in &self.options().parse_callbacks {
+ cb.include_file(&filename);
}
self.deps.insert(filename);
}
@@ -2240,19 +2234,24 @@ If you encounter an error missing from this list, please file an issue or a PR!"
.or_insert_with(|| {
item.expect_type()
.name()
- .and_then(|name| match self.options.parse_callbacks {
- Some(ref cb) => cb.blocklisted_type_implements_trait(
- name,
- derive_trait,
- ),
- // Sized integer types from <stdint.h> get mapped to Rust primitive
- // types regardless of whether they are blocklisted, so ensure that
- // standard traits are considered derivable for them too.
- None => Some(if self.is_stdint_type(name) {
- CanDerive::Yes
+ .and_then(|name| {
+ if self.options.parse_callbacks.is_empty() {
+ // Sized integer types from <stdint.h> get mapped to Rust primitive
+ // types regardless of whether they are blocklisted, so ensure that
+ // standard traits are considered derivable for them too.
+ if self.is_stdint_type(name) {
+ Some(CanDerive::Yes)
+ } else {
+ Some(CanDerive::No)
+ }
} else {
- CanDerive::No
- }),
+ self.options.last_callback(|cb| {
+ cb.blocklisted_type_implements_trait(
+ name,
+ derive_trait,
+ )
+ })
+ }
})
.unwrap_or(CanDerive::No)
})
diff --git a/bindgen/ir/enum_ty.rs b/bindgen/ir/enum_ty.rs
index 059ee012..39677e93 100644
--- a/bindgen/ir/enum_ty.rs
+++ b/bindgen/ir/enum_ty.rs
@@ -102,8 +102,8 @@ impl Enum {
let name = cursor.spelling();
let annotations = Annotations::new(&cursor);
let custom_behavior = ctx
- .parse_callbacks()
- .and_then(|callbacks| {
+ .options()
+ .last_callback(|callbacks| {
callbacks
.enum_variant_behavior(type_name, &name, val)
})
@@ -119,8 +119,8 @@ impl Enum {
});
let new_name = ctx
- .parse_callbacks()
- .and_then(|callbacks| {
+ .options()
+ .last_callback(|callbacks| {
callbacks.enum_variant_name(type_name, &name, val)
})
.or_else(|| {
diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs
index c160ed81..f488b384 100644
--- a/bindgen/ir/function.rs
+++ b/bindgen/ir/function.rs
@@ -664,10 +664,11 @@ impl ClangSubItemParser for Function {
// but seems easy enough to handle it here.
name.push_str("_destructor");
}
- if let Some(callbacks) = context.parse_callbacks() {
- if let Some(nm) = callbacks.generated_name_override(&name) {
- name = nm;
- }
+ if let Some(nm) = context
+ .options()
+ .last_callback(|callbacks| callbacks.generated_name_override(&name))
+ {
+ name = nm;
}
assert!(!name.is_empty(), "Empty function name.");
diff --git a/bindgen/ir/item.rs b/bindgen/ir/item.rs
index 1f4ac154..446d78bd 100644
--- a/bindgen/ir/item.rs
+++ b/bindgen/ir/item.rs
@@ -932,8 +932,8 @@ impl Item {
let name = names.join("_");
let name = if opt.user_mangled == UserMangled::Yes {
- ctx.parse_callbacks()
- .and_then(|callbacks| callbacks.item_name(&name))
+ ctx.options()
+ .last_callback(|callbacks| callbacks.item_name(&name))
.unwrap_or(name)
} else {
name
diff --git a/bindgen/ir/var.rs b/bindgen/ir/var.rs
index daaad8c5..198206b9 100644
--- a/bindgen/ir/var.rs
+++ b/bindgen/ir/var.rs
@@ -182,7 +182,7 @@ impl ClangSubItemParser for Var {
use clang_sys::*;
match cursor.kind() {
CXCursor_MacroDefinition => {
- if let Some(callbacks) = ctx.parse_callbacks() {
+ for callbacks in &ctx.options().parse_callbacks {
match callbacks.will_parse_macro(&cursor.spelling()) {
MacroParsingBehavior::Ignore => {
return Err(ParseError::Continue);
@@ -191,7 +191,7 @@ impl ClangSubItemParser for Var {
}
if cursor.is_macro_function_like() {
- handle_function_macro(&cursor, callbacks);
+ handle_function_macro(&cursor, callbacks.as_ref());
// We handled the macro, skip macro processing below.
return Err(ParseError::Continue);
}
@@ -249,15 +249,15 @@ impl ClangSubItemParser for Var {
true,
ctx,
);
- if let Some(callbacks) = ctx.parse_callbacks() {
+ for callbacks in &ctx.options().parse_callbacks {
callbacks.str_macro(&name, &val);
}
(TypeKind::Pointer(char_ty), VarType::String(val))
}
EvalResult::Int(Wrapping(value)) => {
let kind = ctx
- .parse_callbacks()
- .and_then(|c| c.int_macro(&name, value))
+ .options()
+ .last_callback(|c| c.int_macro(&name, value))
.unwrap_or_else(|| {
default_macro_constant_type(ctx, value)
});
diff --git a/bindgen/lib.rs b/bindgen/lib.rs
index 4d72df0b..5e04acfe 100644
--- a/bindgen/lib.rs
+++ b/bindgen/lib.rs
@@ -1464,7 +1464,7 @@ impl Builder {
mut self,
cb: Box<dyn callbacks::ParseCallbacks>,
) -> Self {
- self.options.parse_callbacks = Some(Rc::from(cb));
+ self.options.parse_callbacks.push(Rc::from(cb));
self
}
@@ -1982,7 +1982,7 @@ struct BindgenOptions {
/// A user-provided visitor to allow customizing different kinds of
/// situations.
- parse_callbacks: Option<Rc<dyn callbacks::ParseCallbacks>>,
+ parse_callbacks: Vec<Rc<dyn callbacks::ParseCallbacks>>,
/// Which kind of items should we generate? By default, we'll generate all
/// of them.
@@ -2160,6 +2160,26 @@ impl BindgenOptions {
pub fn rust_features(&self) -> RustFeatures {
self.rust_features
}
+
+ fn last_callback<T>(
+ &self,
+ f: impl Fn(&dyn callbacks::ParseCallbacks) -> Option<T>,
+ ) -> Option<T> {
+ self.parse_callbacks
+ .iter()
+ .filter_map(|cb| f(cb.as_ref()))
+ .last()
+ }
+
+ fn all_callbacks<T>(
+ &self,
+ f: impl Fn(&dyn callbacks::ParseCallbacks) -> Vec<T>,
+ ) -> Vec<T> {
+ self.parse_callbacks
+ .iter()
+ .flat_map(|cb| f(cb.as_ref()))
+ .collect()
+ }
}
impl Default for BindgenOptions {
@@ -2225,7 +2245,7 @@ impl Default for BindgenOptions {
clang_args: vec![],
input_headers: vec![],
input_header_contents: Default::default(),
- parse_callbacks: None,
+ parse_callbacks: Default::default(),
codegen_config: CodegenConfig::all(),
conservative_inline_namespaces: false,
generate_comments: true,