opencv_binding_generator/
constant.rs1use std::borrow::Cow;
2use std::borrow::Cow::{Borrowed, Owned};
3use std::rc::Rc;
4
5use clang::token::{Token, TokenKind};
6use clang::{Entity, EntityKind, EvaluationResult};
7pub use desc::ConstDesc;
8
9use crate::debug::{DefinitionLocation, LocationName};
10use crate::element::ExcludeKind;
11use crate::type_ref::CppNameStyle;
12use crate::{settings, DefaultElement, Element, NameDebug, StrExt};
13
14mod desc;
15
16pub fn render_constant_cpp(tokens: &[Token]) -> String {
17 tokens
18 .iter()
19 .fold(String::with_capacity(tokens.len() * 8), |out, x| out + &x.get_spelling())
20}
21
22pub fn render_evaluation_result_rust(result: EvaluationResult) -> Value {
23 match result {
24 EvaluationResult::Unexposed => panic!("Can't render evaluation result"),
25 EvaluationResult::SignedInteger(x) => Value {
26 kind: ValueKind::Integer,
27 value: x.to_string(),
28 },
29 EvaluationResult::UnsignedInteger(x) => Value {
30 kind: ValueKind::UnsignedInteger,
31 value: x.to_string(),
32 },
33 EvaluationResult::Float(x) => Value {
34 kind: ValueKind::Double,
35 value: x.to_string(),
36 },
37 EvaluationResult::String(x)
38 | EvaluationResult::ObjCString(x)
39 | EvaluationResult::CFString(x)
40 | EvaluationResult::Other(x) => Value {
41 kind: ValueKind::String,
42 value: format!(r#""{}""#, x.to_string_lossy()),
43 },
44 }
45}
46
47#[derive(Clone, Debug)]
48pub enum Const<'tu> {
49 Clang { entity: Entity<'tu> },
50 Desc(Rc<ConstDesc>),
51}
52
53impl<'tu> Const<'tu> {
54 pub fn new(entity: Entity<'tu>) -> Self {
55 Self::Clang { entity }
56 }
57
58 pub fn new_desc(desc: ConstDesc) -> Self {
59 Self::Desc(Rc::new(desc))
60 }
61
62 pub fn value(&self) -> Option<Cow<'_, Value>> {
63 match self {
64 Self::Clang { entity } => match entity.get_kind() {
65 EntityKind::MacroDefinition => {
66 let tokens = entity.get_range().expect("Can't get macro definition range").tokenize();
67 if tokens.len() <= 1 {
68 None
69 } else {
70 Value::try_from_tokens(&tokens[1..]).map(Owned)
71 }
72 }
73 EntityKind::EnumConstantDecl => Some(Owned(Value {
74 kind: ValueKind::Integer,
75 value: entity
76 .get_enum_constant_value()
77 .expect("Can't get enum constant value")
78 .0
79 .to_string(),
80 })),
81 EntityKind::VarDecl => entity.evaluate().map(render_evaluation_result_rust).map(Owned),
82 _ => unreachable!("Invalid entity type for constant"),
83 },
84 Self::Desc(desc) => Some(Borrowed(desc.value.as_ref())),
85 }
86 }
87}
88
89impl Element for Const<'_> {
90 fn exclude_kind(&self) -> ExcludeKind {
91 match self {
92 Self::Clang { entity } => DefaultElement::exclude_kind(self).with_is_excluded(|| {
93 entity.is_function_like_macro()
94 && !settings::IMPLEMENTED_FUNCTION_LIKE_MACROS.contains(self.cpp_name(CppNameStyle::Reference).as_ref())
95 }),
96 Self::Desc(_) => ExcludeKind::Included,
97 }
98 }
99
100 fn is_system(&self) -> bool {
101 match self {
102 &Self::Clang { entity } => DefaultElement::is_system(entity),
103 Self::Desc(_) => false,
104 }
105 }
106
107 fn is_public(&self) -> bool {
108 match self {
109 &Self::Clang { entity } => DefaultElement::is_public(entity),
110 Self::Desc(_) => true,
111 }
112 }
113
114 fn doc_comment(&self) -> Cow<'_, str> {
115 match self {
116 Self::Clang { entity } => entity.doc_comment(),
117 Self::Desc(desc) => Borrowed(desc.doc_comment.as_ref()),
118 }
119 }
120
121 fn cpp_namespace(&self) -> Cow<'_, str> {
122 match self {
123 &Self::Clang { entity } => DefaultElement::cpp_namespace(entity).into(),
124 Self::Desc(desc) => Borrowed(desc.cpp_fullname.namespace()),
125 }
126 }
127
128 fn cpp_name(&self, style: CppNameStyle) -> Cow<'_, str> {
129 match self {
130 &Self::Clang { entity } => DefaultElement::cpp_name(self, entity, style),
131 Self::Desc(desc) => Borrowed(desc.cpp_fullname.cpp_name_from_fullname(style)),
132 }
133 }
134}
135
136impl<'me> NameDebug<'me> for &'me Const<'_> {
137 fn file_line_name(self) -> LocationName<'me> {
138 match self {
139 Const::Clang { entity } => entity.file_line_name(),
140 Const::Desc(desc) => LocationName::new(DefinitionLocation::Generated, desc.cpp_fullname.as_ref()),
141 }
142 }
143}
144
145#[derive(Clone, Copy, Debug, PartialEq, Eq)]
146pub enum ValueKind {
147 Integer,
148 UnsignedInteger,
149 Usize,
150 Float,
151 Double,
152 String,
153}
154
155#[derive(Clone, Debug)]
156pub struct Value {
157 pub kind: ValueKind,
158 pub value: String,
159}
160
161impl Value {
162 pub fn integer(val: i32) -> Self {
163 Self {
164 kind: ValueKind::Integer,
165 value: val.to_string(),
166 }
167 }
168
169 pub fn try_from_tokens(tokens: &[Token]) -> Option<Self> {
170 let mut out = Value {
171 kind: ValueKind::Integer,
172 value: String::with_capacity(tokens.len() * 8),
173 };
174 for t in tokens {
175 match t.get_kind() {
176 TokenKind::Comment => {
177 out.value.push_str("/* ");
178 out.value.push_str(&t.get_spelling());
179 out.value.push_str(" */");
180 }
181 TokenKind::Identifier => {
182 let spelling = t.get_spelling();
183 if let Some(entity) = t.get_location().get_entity() {
184 if let EntityKind::MacroExpansion = entity.get_kind() {
185 let cnst = Const::new(entity);
186 if cnst.exclude_kind().is_excluded() {
187 return None;
188 }
189 }
190 }
191 if spelling.starts_with("CV_") {
192 out.value += &spelling;
193 } else {
194 return None;
195 }
196 }
197 TokenKind::Keyword => {
198 return None;
199 }
200 TokenKind::Literal => {
201 let spelling = t.get_spelling();
202 if spelling.contains(['"', '\'']) {
203 out.kind = ValueKind::String;
204 out.value += &spelling;
205 } else if spelling.contains('.') {
206 if let Some(float) = spelling.strip_suffix(['F', 'f']) {
207 out.kind = ValueKind::Float;
208 out.value += float;
209 } else {
210 out.kind = ValueKind::Double;
211 out.value += &spelling;
212 }
213 } else if let Some(unsigned_value) = spelling.strip_suffix(['U', 'u']) {
214 out.kind = ValueKind::UnsignedInteger;
215 out.value += unsigned_value;
216 } else {
217 out.value += &spelling;
218 }
219 }
220 TokenKind::Punctuation => {
221 let spelling = t.get_spelling();
222 if spelling == "{" || spelling == "}" {
223 return None;
224 }
225 out.value += &spelling;
226 }
227 }
228 }
229 Some(out)
230 }
231}