Skip to content

Commit 9841600

Browse files
committed
GeneratorEnv rework
1 parent a2e9b15 commit 9841600

9 files changed

+178
-144
lines changed

binding-generator/src/bin/settings-cleanup.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use opencv_binding_generator::{
1111
};
1212

1313
struct FunctionFinder<'tu, 'f> {
14+
pub module: &'tu str,
1415
pub gen_env: GeneratorEnv<'tu>,
1516
pub func_rename_unused: RefCell<&'f mut HashSet<&'static str>>,
1617
pub func_exclude_unused: RefCell<&'f mut HashSet<&'static str>>,
@@ -38,7 +39,7 @@ impl<'tu, 'f> FunctionFinder<'tu, 'f> {
3839

3940
impl<'tu> EntityWalkerVisitor<'tu> for FunctionFinder<'tu, '_> {
4041
fn wants_file(&mut self, path: &Path) -> bool {
41-
opencv_module_from_path(path).map_or(false, |m| m == self.gen_env.module())
42+
opencv_module_from_path(path).map_or(false, |m| m == self.module)
4243
}
4344

4445
fn visit_entity(&mut self, entity: Entity<'tu>) -> ControlFlow<()> {
@@ -110,8 +111,9 @@ fn main() {
110111
for module in modules {
111112
println!(" {module}");
112113
gen.pre_process(&module, false, |root_entity| {
113-
let gen_env = GeneratorEnv::new(root_entity, &module);
114+
let gen_env = GeneratorEnv::global(&module, root_entity);
114115
root_entity.walk_opencv_entities(FunctionFinder {
116+
module: &module,
115117
gen_env,
116118
func_rename_unused: RefCell::new(&mut func_rename_unused),
117119
func_exclude_unused: RefCell::new(&mut func_exclude_unused),

binding-generator/src/class.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -350,18 +350,19 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
350350
out.push(func);
351351
ControlFlow::Continue(())
352352
});
353-
let rust_module = match self {
354-
Class::Clang { gen_env, .. } => gen_env.module(),
355-
Class::Desc(desc) => desc.rust_module.as_ref(),
356-
};
357-
for inject_func_fact in settings::FUNC_INJECT.get(rust_module).into_iter().flatten() {
358-
let inject_func: Func = inject_func_fact();
359-
if let Some(cls) = inject_func.kind().as_class_method() {
360-
if cls == self {
361-
out.push(inject_func);
353+
match self {
354+
Class::Clang { gen_env, .. } => {
355+
for inject_func_fact in &gen_env.settings.func_inject {
356+
let inject_func: Func = inject_func_fact();
357+
if let Some(cls) = inject_func.kind().as_class_method() {
358+
if cls == self {
359+
out.push(inject_func);
360+
}
361+
}
362362
}
363363
}
364-
}
364+
Class::Desc(_) => {}
365+
};
365366
out
366367
}
367368

binding-generator/src/func.rs

+22-11
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ use std::ops::ControlFlow;
66
use std::rc::Rc;
77

88
use clang::{Availability, Entity, EntityKind, ExceptionSpecification};
9-
use once_cell::sync::Lazy;
10-
use regex::bytes::Regex;
11-
129
pub use desc::{FuncCppBody, FuncDesc, FuncRustBody, FuncRustExtern};
1310
pub use func_id::FuncId;
1411
pub use kind::{FuncKind, OperatorKind, ReturnKind};
12+
use once_cell::sync::Lazy;
13+
use regex::bytes::Regex;
1514
use slice_arg_finder::SliceArgFinder;
1615

1716
use crate::comment::strip_doxygen_comment_markers;
@@ -391,13 +390,17 @@ impl<'tu, 'ge> Func<'tu, 'ge> {
391390
}
392391

393392
pub fn safety(&self) -> Safety {
394-
Safety::from_unsafe(
395-
settings::FUNC_UNSAFE.contains(&self.func_id())
396-
|| self.arguments().iter().any(|a| {
397-
let type_ref = a.type_ref();
398-
type_ref.kind().is_rust_by_ptr(type_ref.type_hint()) && !a.is_user_data()
399-
}),
400-
)
393+
// todo move FUNC_UNSAFE to gen_env.settings, but can't do that now because setAllocator is a Desc function and it needs to be unsafe
394+
let out = match self {
395+
Func::Clang { .. } => Safety::from_is_unsafe(settings::FUNC_UNSAFE.contains(&self.func_id())),
396+
Func::Desc(_) => Safety::from_is_unsafe(settings::FUNC_UNSAFE.contains(&self.func_id())),
397+
};
398+
out.or_is_unsafe(|| {
399+
self.arguments().iter().any(|a| {
400+
let type_ref = a.type_ref();
401+
type_ref.kind().is_rust_by_ptr(type_ref.type_hint()) && !a.is_user_data()
402+
})
403+
})
401404
}
402405

403406
pub fn is_default_constructor(&self) -> bool {
@@ -757,7 +760,7 @@ pub enum Safety {
757760
}
758761

759762
impl Safety {
760-
pub fn from_unsafe(is_unsafe: bool) -> Safety {
763+
pub fn from_is_unsafe(is_unsafe: bool) -> Safety {
761764
if is_unsafe {
762765
Self::Unsafe
763766
} else {
@@ -772,6 +775,14 @@ impl Safety {
772775
}
773776
}
774777

778+
/// Returns `Safe` only if both `self` and `other_is_unsafe` are `Safe`, otherwise returns `Unsafe`
779+
pub fn or_is_unsafe(self, other_is_unsafe: impl FnOnce() -> bool) -> Safety {
780+
match self {
781+
Safety::Safe => Self::from_is_unsafe(other_is_unsafe()),
782+
Safety::Unsafe => Self::Unsafe,
783+
}
784+
}
785+
775786
/// Returns `""` or `"unsafe "`, for usage for unsafe blocks within functions with `self` safety
776787
pub fn rust_block_safety_qual(self) -> &'static str {
777788
match self {

binding-generator/src/generator.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub trait GeneratorVisitor<'tu>: Sized {
7878
/// all or is internal) and calls the corresponding method in [GeneratorVisitor] based on their type. This is the 2nd pass of the
7979
/// binding generation.
8080
struct OpenCvWalker<'tu, 'r, V> {
81+
module: &'r str,
8182
opencv_module_header_dir: &'r Path,
8283
visitor: V,
8384
gen_env: GeneratorEnv<'tu>,
@@ -159,7 +160,7 @@ impl<'tu, V: GeneratorVisitor<'tu>> EntityWalkerVisitor<'tu> for OpenCvWalker<'t
159160
// method of extracting comments
160161
let mut comment = String::with_capacity(2048);
161162
let mut found_module_comment = false;
162-
let module_path = self.opencv_module_header_dir.join(format!("{}.hpp", self.gen_env.module()));
163+
let module_path = self.opencv_module_header_dir.join(format!("{}.hpp", self.module));
163164
if let Ok(module_file) = File::open(module_path) {
164165
let f = BufReader::new(module_file);
165166
let mut defgroup_found = false;
@@ -188,26 +189,25 @@ impl<'tu, V: GeneratorVisitor<'tu>> EntityWalkerVisitor<'tu> for OpenCvWalker<'t
188189
if found_module_comment {
189190
self.visitor.visit_module_comment(comment);
190191
}
191-
for inject_func_fact in settings::FUNC_INJECT.get(self.gen_env.module()).into_iter().flatten() {
192+
for inject_func_fact in &self.gen_env.settings.func_inject {
192193
let inject_func: Func = inject_func_fact();
193194
if !inject_func.kind().as_class_method().is_some() {
194195
self.visitor.visit_func(inject_func);
195196
}
196197
}
197-
if let Some(tweaks) = settings::GENERATOR_MODULE_TWEAKS.get(self.gen_env.module()) {
198-
for generated in &tweaks.generate_types {
199-
if let Ok(generated) = GeneratedType::try_from(generated()) {
200-
self.visitor.visit_generated_type(generated);
201-
}
198+
for generated in &self.gen_env.settings.generator_module_tweaks.generate_types {
199+
if let Ok(generated) = GeneratedType::try_from(generated()) {
200+
self.visitor.visit_generated_type(generated);
202201
}
203202
}
204203
self.visitor.goodbye();
205204
}
206205
}
207206

208207
impl<'tu, 'r, V: GeneratorVisitor<'tu>> OpenCvWalker<'tu, 'r, V> {
209-
pub fn new(opencv_module_header_dir: &'r Path, visitor: V, gen_env: GeneratorEnv<'tu>) -> Self {
208+
pub fn new(module: &'r str, opencv_module_header_dir: &'r Path, visitor: V, gen_env: GeneratorEnv<'tu>) -> Self {
210209
Self {
210+
module,
211211
opencv_module_header_dir,
212212
visitor,
213213
gen_env,
@@ -468,8 +468,8 @@ impl Generator {
468468
/// Runs the full binding generation process using the supplied `visitor`
469469
pub fn generate(&self, module: &str, visitor: impl for<'tu> GeneratorVisitor<'tu>) {
470470
self.pre_process(module, true, |root_entity| {
471-
let gen_env = GeneratorEnv::new(root_entity, module);
472-
let opencv_walker = OpenCvWalker::new(&self.opencv_module_header_dir, visitor, gen_env);
471+
let gen_env = GeneratorEnv::global(module, root_entity);
472+
let opencv_walker = OpenCvWalker::new(module, &self.opencv_module_header_dir, visitor, gen_env);
473473
root_entity.walk_opencv_entities(opencv_walker);
474474
});
475475
}

binding-generator/src/generator_env.rs

+27-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::rc::Rc;
1111
use clang::{Entity, EntityKind, EntityVisitResult};
1212

1313
use crate::class::ClassKind;
14+
use crate::settings::Settings;
1415
use crate::type_ref::CppNameStyle;
1516
use crate::{
1617
is_opencv_path, opencv_module_from_path, settings, Class, Element, EntityWalkerExt, EntityWalkerVisitor, MemoizeMap,
@@ -104,6 +105,7 @@ struct ExportIdx {
104105
///
105106
/// This is 1st pass of the analysis. It performs the collection of the necessary auxiliary data like which descendants a class has.
106107
struct GeneratorEnvPopulator<'tu, 'ge> {
108+
module: &'tu str,
107109
gen_env: &'ge mut GeneratorEnv<'tu>,
108110
}
109111

@@ -133,7 +135,7 @@ impl<'tu> GeneratorEnvPopulator<'tu, '_> {
133135

134136
impl<'tu> EntityWalkerVisitor<'tu> for GeneratorEnvPopulator<'tu, '_> {
135137
fn wants_file(&mut self, path: &Path) -> bool {
136-
is_opencv_path(path) || opencv_module_from_path(path).map_or(false, |m| m == self.gen_env.module())
138+
is_opencv_path(path) || opencv_module_from_path(path).map_or(false, |m| m == self.module)
137139
}
138140

139141
fn visit_entity(&mut self, entity: Entity<'tu>) -> ControlFlow<()> {
@@ -169,8 +171,6 @@ impl<'tu> EntityWalkerVisitor<'tu> for GeneratorEnvPopulator<'tu, '_> {
169171
/// This is partially pre-populated in an additional pass before the generation to provide some necessary data that's not available
170172
/// at the generation moment. E.g. list of descendants of a particular class.
171173
pub struct GeneratorEnv<'tu> {
172-
/// The name of the module that's currently being generated
173-
module: &'tu str,
174174
export_map: HashMap<ExportIdx, ExportConfig>,
175175
rename_map: HashMap<ExportIdx, RenameConfig>,
176176
pub func_names: NamePool,
@@ -179,28 +179,40 @@ pub struct GeneratorEnv<'tu> {
179179
/// Cache of the calculated [ClassKind]s
180180
class_kind_cache: MemoizeMap<String, Option<ClassKind>>,
181181
descendants: HashMap<String, HashSet<Entity<'tu>>>,
182+
pub settings: Settings,
182183
}
183184

184185
impl<'tu> GeneratorEnv<'tu> {
185-
pub fn new(root_entity: Entity<'tu>, module: &'tu str) -> Self {
186+
pub fn empty() -> Self {
187+
Self {
188+
export_map: HashMap::new(),
189+
rename_map: HashMap::new(),
190+
func_names: NamePool::with_capacity(0),
191+
func_comments: HashMap::new(),
192+
class_kind_cache: MemoizeMap::new(HashMap::new()),
193+
descendants: HashMap::new(),
194+
settings: Settings::empty(),
195+
}
196+
}
197+
198+
/// [GeneratorEnv] with the global settings for the regular working mode
199+
pub fn global(module: &'tu str, root_entity: Entity<'tu>) -> Self {
186200
let mut out = Self {
187-
module,
188201
export_map: HashMap::with_capacity(1024),
189202
rename_map: HashMap::with_capacity(64),
190203
func_names: NamePool::with_capacity(512),
191204
func_comments: HashMap::with_capacity(2048),
192205
class_kind_cache: MemoizeMap::new(HashMap::with_capacity(32)),
193206
descendants: HashMap::with_capacity(16),
207+
settings: Settings::for_module(module),
194208
};
195-
root_entity.walk_opencv_entities(GeneratorEnvPopulator { gen_env: &mut out });
209+
root_entity.walk_opencv_entities(GeneratorEnvPopulator {
210+
module,
211+
gen_env: &mut out,
212+
});
196213
out
197214
}
198215

199-
/// The name of the module that's currently being generated
200-
pub fn module(&self) -> &str {
201-
self.module
202-
}
203-
204216
fn key(entity: Entity) -> ExportIdx {
205217
let (loc, line_offset) = if entity.get_kind() == EntityKind::MacroExpansion {
206218
// sometimes CV_EXPORT macros are located on a separate line so for those we compensate the offset
@@ -353,11 +365,15 @@ impl fmt::Debug for GeneratorEnv<'_> {
353365
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
354366
f.debug_struct("GeneratorEnv")
355367
.field("export_map", &format!("{} elements", self.export_map.len()))
368+
.field("rename_map", &format!("{} elements", self.rename_map.len()))
369+
.field("func_names", &format!("{} elements", self.func_names.len()))
356370
.field("func_comments", &format!("{} elements", self.func_comments.len()))
357371
.field(
358372
"class_kind_cache",
359373
&format!("{} elements", self.class_kind_cache.borrow().len()),
360374
)
375+
.field("descendants", &format!("{} elements", self.descendants.len()))
376+
.field("settings", &self.settings)
361377
.finish()
362378
}
363379
}

binding-generator/src/name_pool.rs

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ impl NamePool {
1414
}
1515
}
1616

17+
pub fn len(&self) -> usize {
18+
self.names.len()
19+
}
20+
1721
pub fn make_unique_name(&mut self, name: &mut Cow<str>) -> MakeUniqueNameResult {
1822
let mut out = MakeUniqueNameResult::Unchanged;
1923
while self.names.contains(name.as_ref()) {

binding-generator/src/settings.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,24 @@
22

33
use std::collections::{BTreeSet, HashMap, HashSet};
44

5-
use once_cell::sync::Lazy;
6-
75
pub use argument_names::{ARGUMENT_NAMES_MULTIPLE_SLICE, ARGUMENT_NAMES_NOT_SLICE, ARGUMENT_NAMES_USERDATA};
86
pub use argument_override::{ARGUMENT_OVERRIDE, ARG_OVERRIDE_SELF, RETURN_OVERRIDE};
97
pub use element_exclude_kind::ELEMENT_EXCLUDE_KIND;
108
pub use element_export_tweak::ELEMENT_EXPORT_TWEAK;
119
pub use force_infallible::FORCE_INFALLIBLE;
1210
pub use func_cfg_attr::FUNC_CFG_ATTR;
1311
pub use func_exclude::FUNC_EXCLUDE;
14-
pub use func_inject::{FuncFactory, FUNC_INJECT};
12+
pub use func_inject::{func_inject_factory, FuncFactory};
1513
pub use func_rename::FUNC_RENAME;
1614
pub use func_replace::{FuncInheritFactory, FUNC_REPLACE};
1715
pub use func_specialize::{TypeRefFactory, FUNC_SPECIALIZE};
1816
pub use func_unsafe::FUNC_UNSAFE;
19-
pub use generator_module_tweaks::{ModuleTweak, GENERATOR_MODULE_TWEAKS};
17+
pub use generator_module_tweaks::{generator_module_tweaks_factory, ModuleTweak};
2018
pub use implemented::{
2119
IMPLEMENTED_CONST_GENERICS, IMPLEMENTED_FUNCTION_LIKE_MACROS, IMPLEMENTED_GENERICS, IMPLEMENTED_MANUAL_DEBUG,
2220
IMPLEMENTED_SYSTEM_CLASSES,
2321
};
22+
use once_cell::sync::Lazy;
2423

2524
mod argument_names;
2625
mod argument_override;
@@ -37,6 +36,29 @@ mod func_unsafe;
3736
mod generator_module_tweaks;
3837
mod implemented;
3938

39+
/// Injectable global and module level overrides, todo: migrate the global statics to this over time
40+
#[derive(Debug)]
41+
pub struct Settings {
42+
pub func_inject: Vec<FuncFactory>,
43+
pub generator_module_tweaks: ModuleTweak,
44+
}
45+
46+
impl Settings {
47+
pub fn empty() -> Self {
48+
Self {
49+
func_inject: vec![],
50+
generator_module_tweaks: ModuleTweak::empty(),
51+
}
52+
}
53+
54+
pub fn for_module(module: &str) -> Self {
55+
Self {
56+
func_inject: func_inject_factory(module),
57+
generator_module_tweaks: generator_module_tweaks_factory(module),
58+
}
59+
}
60+
}
61+
4062
// fixme, generalize, make it use constant::ValueKind
4163
pub static CONST_TYPE_USIZE: Lazy<HashSet<&str>> = Lazy::new(|| HashSet::from(["Mat_AUTO_STEP"]));
4264

binding-generator/src/settings/func_inject.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
use std::collections::HashMap;
2-
3-
use once_cell::sync::Lazy;
4-
51
use crate::class::ClassDesc;
62
use crate::field::{Field, FieldDesc};
73
use crate::func::{FuncCppBody, FuncDesc, FuncKind, FuncRustBody, ReturnKind};
@@ -12,11 +8,9 @@ use crate::Func;
128

139
pub type FuncFactory = fn() -> Func<'static, 'static>;
1410

15-
/// (module name, FuncFactory)
16-
pub static FUNC_INJECT: Lazy<HashMap<&str, Vec<FuncFactory>>> = Lazy::new(|| {
17-
HashMap::from([(
18-
"core",
19-
vec![
11+
pub fn func_inject_factory(module: &str) -> Vec<FuncFactory> {
12+
match module {
13+
"core" => vec![
2014
(|| {
2115
Func::new_desc(FuncDesc::new(
2216
FuncKind::InstanceMethod(ClassDesc::cv_matconstiterator()),
@@ -82,5 +76,6 @@ pub static FUNC_INJECT: Lazy<HashMap<&str, Vec<FuncFactory>>> = Lazy::new(|| {
8276
))
8377
},
8478
],
85-
)])
86-
});
79+
_ => vec![],
80+
}
81+
}

0 commit comments

Comments
 (0)