opencv_binding_generator/writer/rust_native/
element.rs

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