Skip to main content

opencv_binding_generator/writer/rust_native/
constant.rs

1use std::borrow::Cow;
2use std::borrow::Cow::{Borrowed, Owned};
3use std::collections::HashMap;
4use std::sync::LazyLock;
5
6use clang::EntityKind;
7use semver::Version;
8
9use super::RustNativeGeneratedElement;
10use super::element::{DefaultRustNativeElement, RustElement};
11use crate::constant::{Value, ValueKind};
12use crate::debug::NameDebug;
13use crate::type_ref::{FishStyle, NameStyle};
14use crate::{CompiledInterpolation, Const, StrExt, SupportedModule, settings};
15
16impl RustElement for Const<'_> {
17	fn rust_module(&self) -> SupportedModule {
18		match self {
19			&Self::Clang { entity } => DefaultRustNativeElement::rust_module(entity),
20			Self::Desc(desc) => desc.rust_module,
21		}
22	}
23
24	fn rust_name(&self, style: NameStyle) -> Cow<'_, str> {
25		match self {
26			&Self::Clang { entity } => {
27				let mut out = DefaultRustNativeElement::rust_name(self, entity, style);
28				if let Some(without_suffix) = out.strip_suffix("_OCVRS_OVERRIDE") {
29					let new_len = without_suffix.len();
30					out.truncate(new_len);
31				}
32				out.into()
33			}
34			Self::Desc(_) => match style {
35				NameStyle::Declaration => self.rust_leafname(FishStyle::No),
36				NameStyle::Reference(fish_style) => format!(
37					"{}::{}",
38					DefaultRustNativeElement::rust_module_reference(self),
39					self.rust_leafname(fish_style)
40				)
41				.into(),
42			},
43		}
44	}
45}
46
47impl RustNativeGeneratedElement for Const<'_> {
48	fn element_safe_id(&self) -> String {
49		format!("{}-{}", self.rust_module().opencv_name(), self.rust_name(NameStyle::decl()))
50	}
51
52	fn gen_rust(&self, opencv_version: &Version) -> String {
53		static RUST_TPL: LazyLock<CompiledInterpolation> =
54			LazyLock::new(|| include_str!("tpl/const/rust.tpl.rs").compile_interpolation());
55
56		let parent_is_class = match self {
57			&Self::Clang { entity } => entity
58				.get_lexical_parent()
59				.is_some_and(|p| matches!(p.get_kind(), EntityKind::ClassDecl | EntityKind::StructDecl)),
60			Self::Desc(_) => false,
61		};
62		let name = if parent_is_class {
63			self.rust_leafname(FishStyle::No)
64		} else {
65			self.rust_name(NameStyle::decl())
66		};
67
68		if let Some(value) = self.value() {
69			let typ = settings::CONST_TYPE_OVERRIDE
70				.get(name.as_ref())
71				.unwrap_or(&value.kind)
72				.rust_type();
73			RUST_TPL.interpolate(&HashMap::from([
74				("doc_comment", Owned(self.rust_doc_comment("///", opencv_version))),
75				("debug", self.get_debug().into()),
76				("name", name),
77				("type", typ.into()),
78				("value", value.rust_render()),
79			]))
80		} else {
81			"".to_string()
82		}
83	}
84}
85
86pub trait ValueKindExt {
87	fn rust_type(self) -> &'static str;
88}
89
90impl ValueKindExt for ValueKind {
91	fn rust_type(self) -> &'static str {
92		match self {
93			ValueKind::Integer => "i32",
94			ValueKind::UnsignedInteger => "u32",
95			ValueKind::Usize => "usize",
96			ValueKind::Float => "f32",
97			ValueKind::Double => "f64",
98			ValueKind::String => "&str",
99		}
100	}
101}
102
103pub trait ValueExt {
104	fn rust_render(&self) -> Cow<'_, str>;
105}
106
107impl ValueExt for Value {
108	fn rust_render(&self) -> Cow<'_, str> {
109		match self.kind {
110			ValueKind::Float | ValueKind::Double if !self.value.contains('.') => Owned(format!("{}.", self.value)),
111			ValueKind::Integer => {
112				if let Some(no_prefix) = self.value.strip_prefix("0x")
113					&& i32::from_str_radix(no_prefix, 16).is_err()
114				{
115					Owned(format!("{}u32 as i32", self.value))
116				} else {
117					Borrowed(&self.value)
118				}
119			}
120			ValueKind::UnsignedInteger | ValueKind::Usize | ValueKind::Float | ValueKind::Double | ValueKind::String => {
121				Borrowed(&self.value)
122			}
123		}
124	}
125}