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