diff options
author | Christian Poveda Ruiz <31802960+pvdrz@users.noreply.github.com> | 2022-11-02 13:46:22 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-02 13:46:22 -0500 |
commit | a673a6bc9b83675a7468379e79dcf5d5659c4623 (patch) | |
tree | 5bf1b4d228bd8ff451d790c85cf4033e49cd9ff2 | |
parent | 83426897af20d938fb4dca879d54de456ab96d6b (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.md | 2 | ||||
-rw-r--r-- | bindgen/codegen/mod.rs | 21 | ||||
-rw-r--r-- | bindgen/ir/context.rs | 39 | ||||
-rw-r--r-- | bindgen/ir/enum_ty.rs | 8 | ||||
-rw-r--r-- | bindgen/ir/function.rs | 9 | ||||
-rw-r--r-- | bindgen/ir/item.rs | 4 | ||||
-rw-r--r-- | bindgen/ir/var.rs | 10 | ||||
-rw-r--r-- | bindgen/lib.rs | 26 |
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, |