opencv_binding_generator/
walker.rs1use std::ops::ControlFlow;
2use std::path::Path;
3
4use clang::{Entity, EntityKind, EntityVisitResult};
5
6use crate::entity::ControlFlowExt;
7
8pub trait EntityWalkerVisitor<'tu>: Sized {
10 #[allow(unused)]
12 fn wants_file(&mut self, path: &Path) -> bool {
13 true
14 }
15
16 fn visit_entity(&mut self, entity: Entity<'tu>) -> ControlFlow<()>;
18
19 fn goodbye(self) {}
21}
22
23pub trait EntityWalkerExt<'tu> {
25 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 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}