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