opencv_binding_generator/writer/rust_native/
element.rs1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::ops::ControlFlow;
4
5use clang::{Entity, EntityKind};
6
7use super::comment::RenderComment;
8use crate::type_ref::FishStyle;
9use crate::{
10 opencv_module_from_path, reserved_rename, settings, CppNameStyle, Element, EntityExt, GeneratedType, IteratorExt, NameStyle,
11 StringExt, SupportedModule,
12};
13
14pub struct DefaultRustNativeElement;
15
16impl DefaultRustNativeElement {
17 pub fn rust_module(entity: Entity) -> SupportedModule {
18 entity
19 .get_location()
20 .expect("Can't get location")
21 .get_spelling_location()
22 .file
23 .and_then(|file| opencv_module_from_path(&file.get_path()))
24 .map_or(SupportedModule::Core, |m| rust_module_hack(entity, m))
25 }
26
27 pub fn rust_module_reference(this: &(impl RustElement + ?Sized)) -> Cow<'_, str> {
28 let module = this.rust_module();
29 let module_rust_safe_name = module.rust_safe_name();
30 if settings::STATIC_RUST_MODULES.contains(module_rust_safe_name) {
31 module_rust_safe_name.into()
32 } else {
33 format!("crate::{module_rust_safe_name}").into()
34 }
35 }
36
37 pub fn rust_leafname(this: &(impl Element + ?Sized)) -> Cow<'_, str> {
38 reserved_rename(this.cpp_name(CppNameStyle::Declaration))
39 }
40
41 pub fn rust_name(this: &(impl RustElement + ?Sized), entity: Entity, name_style: NameStyle) -> String {
42 let mut parts = Vec::with_capacity(4);
43 parts.push(this.rust_leafname(name_style.turbo_fish_style()));
44 let mut entity = entity;
45 let module = Self::rust_module(entity);
46 while let Some(parent) = entity.get_semantic_parent() {
47 match parent.get_kind() {
48 EntityKind::ClassDecl | EntityKind::StructDecl | EntityKind::ClassTemplate => {
49 let parent_name = parent.get_name().expect("Can't get parent name");
50 if parts.last().is_none_or(|last| last != &parent_name) {
51 parts.push(parent_name.into());
52 }
53 }
54 EntityKind::EnumDecl => {
55 if parent.is_scoped() {
56 parts.push(parent.get_name().expect("Can't get parent name").into());
57 }
58 }
59 EntityKind::TranslationUnit | EntityKind::UnexposedDecl | EntityKind::FunctionTemplate => break,
60 EntityKind::Namespace => {
61 let parent_namespace = parent.get_name().expect("Can't get parent name");
62 let no_skip_prefix = settings::NO_SKIP_NAMESPACE_IN_LOCALNAME
63 .get(&Some(module))
64 .and_then(|module_specific| module_specific.get(parent_namespace.as_str()))
65 .or_else(|| {
66 settings::NO_SKIP_NAMESPACE_IN_LOCALNAME
67 .get(&None)
68 .and_then(|generic| generic.get(parent_namespace.as_str()))
69 });
70 if let Some(&prefix) = no_skip_prefix {
71 parts.push(prefix.into());
72 }
73 }
74 EntityKind::Constructor | EntityKind::FunctionDecl | EntityKind::Method | EntityKind::NotImplemented => {}
75 _ => unreachable!("Can't get kind of parent: {parent:#?} for element: {entity:#?}"),
76 }
77 entity = parent;
78 }
79 let decl_name = parts.into_iter().rev().join("_");
80 match name_style {
81 NameStyle::Declaration => decl_name,
82 NameStyle::Reference(_) => {
83 let mut out = this.rust_module_reference().into_owned();
84 out.extend_sep("::", &decl_name);
85 out
86 }
87 }
88 }
89}
90
91pub trait RustNativeGeneratedElement {
92 fn element_order(&self) -> u8 {
94 50
95 }
96
97 fn element_safe_id(&self) -> String;
98
99 fn gen_rust(&self, _opencv_version: &str) -> String {
100 "".to_string()
101 }
102
103 fn gen_rust_externs(&self) -> String {
104 "".to_string()
105 }
106
107 fn gen_cpp(&self) -> String {
108 "".to_string()
109 }
110}
111
112pub trait RustElement: Element {
113 fn rust_module(&self) -> SupportedModule;
114
115 fn rust_module_reference(&self) -> Cow<'_, str> {
116 DefaultRustNativeElement::rust_module_reference(self)
117 }
118
119 fn rust_name(&self, style: NameStyle) -> Cow<'_, str>;
120
121 fn rust_leafname(&self, _fish_style: FishStyle) -> Cow<'_, str> {
126 DefaultRustNativeElement::rust_leafname(self)
127 }
128
129 fn rust_doc_comment(&self, comment_marker: &str, opencv_version: &str) -> String {
130 RenderComment::new(self.doc_comment().into_owned(), opencv_version)
131 .render_with_comment_marker(comment_marker)
132 .into_owned()
133 }
134}
135
136pub trait DebugRust {
137 type DebugType: Debug;
138
139 fn dbg_rust(self) -> Self::DebugType;
140}
141
142impl<'ne, 'tu: 'ne, 'ge: 'ne> AsRef<dyn RustNativeGeneratedElement + 'ne> for GeneratedType<'tu, 'ge> {
143 fn as_ref(&self) -> &(dyn RustNativeGeneratedElement + 'ne) {
144 match self {
145 GeneratedType::Vector(vec) => vec,
146 GeneratedType::SmartPtr(ptr) => ptr,
147 GeneratedType::Tuple(tuple) => tuple,
148 GeneratedType::AbstractRefWrapper(aref) => aref,
149 }
150 }
151}
152
153fn rust_module_hack(entity: Entity, module_from_path: SupportedModule) -> SupportedModule {
159 match module_from_path {
160 SupportedModule::Video => {
161 let break_res = entity.walk_parents(|parent| match parent.get_kind() {
162 EntityKind::Namespace if parent.is_inline_namespace() && parent.get_name().is_some_and(|n| n == "tracking") => {
163 ControlFlow::Break(SupportedModule::Tracking)
164 }
165 _ => ControlFlow::Continue(()),
166 });
167 match break_res {
169 ControlFlow::Break(m) => Some(m),
170 ControlFlow::Continue(_) => None,
171 }
172 .unwrap_or(module_from_path)
173 }
174 _ => module_from_path,
175 }
176}