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					_ => {
61						unreachable!("Unsupported decl for file: {:#?}", root_decl)
62					}
63				}
64				.into_entity_visit_result()
65			} else {
66				EntityVisitResult::Continue
67			}
68		});
69		visitor.goodbye();
70	}
71}
72
73fn visit_cv_namespace<'tu>(ns: Entity<'tu>, visitor: &mut impl EntityWalkerVisitor<'tu>) -> ControlFlow<()> {
74	let is_interrupted = ns.visit_children(|decl, _| {
75		match decl.get_kind() {
76			EntityKind::Namespace => visit_cv_namespace(decl, visitor),
77			EntityKind::ClassDecl
78			| EntityKind::ClassTemplate
79			| EntityKind::ClassTemplatePartialSpecialization
80			| EntityKind::StructDecl
81			| EntityKind::EnumDecl
82			| EntityKind::FunctionDecl
83			| EntityKind::TypedefDecl
84			| EntityKind::VarDecl
85			| EntityKind::TypeAliasDecl => visitor.visit_entity(decl),
86			EntityKind::Constructor
87			| EntityKind::ConversionFunction
88			| EntityKind::Destructor
89			| EntityKind::Method
90			| EntityKind::UnexposedDecl
91			| EntityKind::FunctionTemplate
92			| EntityKind::UsingDeclaration
93			| EntityKind::UsingDirective
94			| EntityKind::TypeAliasTemplateDecl
95			| EntityKind::LinkageSpec => {
96				/* ignoring */
97				ControlFlow::Continue(())
98			}
99			_ => {
100				unreachable!("Unsupported decl for OpenCV namespace: {:#?}", decl)
101			}
102		}
103		.into_entity_visit_result()
104	});
105	ControlFlow::continue_until(is_interrupted)
106}