opencv_binding_generator/
walker.rs

1use std::ops::ControlFlow;
2use std::path::Path;
3
4use clang::{Entity, EntityKind, EntityVisitResult};
5
6use crate::entity::ControlFlowExt;
7
8/// Visitor to be used in conjunction with [EntityWalker]
9pub trait EntityWalkerVisitor<'tu>: Sized {
10	/// Check whether the visitor is interested in entities from the specified file
11	#[allow(unused)]
12	fn wants_file(&mut self, path: &Path) -> bool {
13		true
14	}
15
16	/// Pass a supported [Entity] to the visitor
17	fn visit_entity(&mut self, entity: Entity<'tu>) -> ControlFlow<()>;
18
19	/// Called at the end of the visitation
20	fn goodbye(self) {}
21}
22
23/// Trait to recursively visit every clang [Entity] supported by the OpenCV binding generator
24pub trait EntityWalkerExt<'tu> {
25	/// Recursively visits every clang [Entity] supported by the OpenCV binding generator starting from the `self`
26	fn walk_opencv_entities(self, visitor: impl EntityWalkerVisitor<'tu>);
27}
28
29impl<'tu> EntityWalkerExt<'tu> for Entity<'tu> {
30	fn walk_opencv_entities(self, mut visitor: impl EntityWalkerVisitor<'tu>) {
31		self.visit_children(|root_decl, _| {
32			let visitor_wants = root_decl
33				.get_location()
34				.and_then(|loc| loc.get_file_location().file.map(|f| f.get_path()))
35				.filter(|file| visitor.wants_file(file))
36				.is_some();
37			if visitor_wants {
38				match root_decl.get_kind() {
39					EntityKind::Namespace if root_decl.get_name().is_some_and(|name| name.starts_with("cv")) => {
40						visit_cv_namespace(root_decl, &mut visitor)
41					}
42					EntityKind::MacroDefinition | EntityKind::MacroExpansion | EntityKind::EnumDecl | EntityKind::TypedefDecl => {
43						visitor.visit_entity(root_decl)
44					}
45					EntityKind::Namespace
46					| EntityKind::FunctionDecl
47					| EntityKind::InclusionDirective
48					| EntityKind::UnionDecl
49					| EntityKind::UnexposedDecl
50					| EntityKind::StructDecl
51					| EntityKind::Constructor
52					| EntityKind::Method
53					| EntityKind::FunctionTemplate
54					| EntityKind::ConversionFunction
55					| EntityKind::ClassTemplate
56					| EntityKind::ClassDecl
57					| EntityKind::Destructor
58					| EntityKind::LinkageSpec
59					| EntityKind::VarDecl => ControlFlow::Continue(()),
60					_ => unreachable!("Unsupported decl for file: {:#?}", root_decl),
61				}
62				.into_entity_visit_result()
63			} else {
64				EntityVisitResult::Continue
65			}
66		});
67		visitor.goodbye();
68	}
69}
70
71fn visit_cv_namespace<'tu>(ns: Entity<'tu>, visitor: &mut impl EntityWalkerVisitor<'tu>) -> ControlFlow<()> {
72	let is_interrupted = ns.visit_children(|decl, _| {
73		match decl.get_kind() {
74			EntityKind::Namespace => visit_cv_namespace(decl, visitor),
75			EntityKind::ClassDecl
76			| EntityKind::ClassTemplate
77			| EntityKind::ClassTemplatePartialSpecialization
78			| EntityKind::StructDecl
79			| EntityKind::EnumDecl
80			| EntityKind::FunctionDecl
81			| EntityKind::TypedefDecl
82			| EntityKind::VarDecl
83			| EntityKind::TypeAliasDecl => visitor.visit_entity(decl),
84			EntityKind::Constructor
85			| EntityKind::ConversionFunction
86			| EntityKind::Destructor
87			| EntityKind::Method
88			| EntityKind::UnexposedDecl
89			| EntityKind::FunctionTemplate
90			| EntityKind::UsingDeclaration
91			| EntityKind::UsingDirective
92			| EntityKind::TypeAliasTemplateDecl
93			| EntityKind::LinkageSpec => {
94				/* ignoring */
95				ControlFlow::Continue(())
96			}
97			_ => unreachable!("Unsupported decl for OpenCV namespace: {:#?}", decl),
98		}
99		.into_entity_visit_result()
100	});
101	ControlFlow::continue_until(is_interrupted)
102}