opencv_binding_generator/writer/rust_native/
constant.rs1use 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}