Skip to main content

opencv_binding_generator/type_ref/
desc.rs

1use std::cell::LazyCell;
2use std::rc::Rc;
3use std::sync::LazyLock;
4
5use clang::{Entity, EntityKind, Type, TypeKind};
6use regex::bytes::{Captures, Regex};
7
8use crate::class::ClassDesc;
9use crate::function::Function;
10use crate::smart_ptr::{SmartPtr, SmartPtrDesc};
11use crate::tuple::Tuple;
12use crate::type_ref::{Constness, TemplateArg, TypeRef, TypeRefKind, TypeRefTypeHint};
13use crate::typedef::{NewTypedefResult, TypedefDesc};
14use crate::vector::{Vector, VectorDesc};
15use crate::{settings, Class, CppNameStyle, Element, Enum, GeneratorEnv, StringExt, Typedef};
16
17#[derive(Clone, Debug)]
18pub struct TypeRefDesc<'tu, 'ge> {
19	pub kind: TypeRefKind<'tu, 'ge>,
20	pub inherent_constness: Constness,
21	pub type_hint: TypeRefTypeHint,
22	pub template_specialization_args: Rc<[TemplateArg<'tu, 'ge>]>,
23}
24
25impl<'tu, 'ge> TypeRefDesc<'tu, 'ge> {
26	pub fn new(kind: TypeRefKind<'tu, 'ge>, inherent_constness: Constness) -> Self {
27		Self {
28			kind,
29			inherent_constness,
30			type_hint: TypeRefTypeHint::None,
31			template_specialization_args: Rc::new([]),
32		}
33	}
34
35	pub fn try_primitive(cpp_name: &str) -> Option<TypeRef<'tu, 'ge>> {
36		let names = match cpp_name {
37			"void" => Some(TypeKind::Void),
38			"bool" => Some(TypeKind::Bool),
39			"char" => Some(TypeKind::CharS),
40			"signed char" => Some(TypeKind::SChar),
41			"unsigned char" => Some(TypeKind::UChar),
42			"wchar_t" => Some(TypeKind::WChar),
43			"char16_t" => Some(TypeKind::Char16),
44			"char32_t" => Some(TypeKind::Char32),
45			"short" => Some(TypeKind::Short),
46			"unsigned short" => Some(TypeKind::UShort),
47			"int" => Some(TypeKind::Int),
48			"unsigned int" => Some(TypeKind::UInt),
49			"long" => Some(TypeKind::Long),
50			"unsigned long" => Some(TypeKind::ULong),
51			"long long" => Some(TypeKind::LongLong),
52			"unsigned long long" => Some(TypeKind::ULongLong),
53			"__int128_t" => Some(TypeKind::Int128),
54			"__uint128_t" => Some(TypeKind::UInt128),
55			"float" => Some(TypeKind::Float),
56			"double" => Some(TypeKind::Double),
57			_ => None,
58		};
59		names
60			.and_then(TypeRefKind::try_from_clang_primitive)
61			.or_else(|| {
62				settings::PRIMITIVE_TYPEDEFS
63					.get(cpp_name)
64					.map(|(rust, cpp)| TypeRefKind::Primitive(rust, cpp))
65			})
66			.map(|type_ref_kind| TypeRef::new_desc(TypeRefDesc::new(type_ref_kind, Constness::Mut)))
67	}
68
69	pub fn void() -> TypeRef<'tu, 'ge> {
70		Self::try_primitive("void").expect("Static primitive type")
71	}
72
73	pub fn bool() -> TypeRef<'tu, 'ge> {
74		Self::try_primitive("bool").expect("Static primitive type")
75	}
76
77	pub fn schar() -> TypeRef<'tu, 'ge> {
78		Self::try_primitive("signed char").expect("Static primitive type")
79	}
80
81	pub fn char() -> TypeRef<'tu, 'ge> {
82		Self::try_primitive("char").expect("Static primitive type")
83	}
84
85	pub fn char_ptr() -> TypeRef<'tu, 'ge> {
86		TypeRef::new_pointer(Self::char())
87	}
88
89	pub fn char_const_ptr() -> TypeRef<'tu, 'ge> {
90		TypeRef::new_pointer(Self::char().with_inherent_constness(Constness::Const))
91	}
92
93	pub fn uchar() -> TypeRef<'tu, 'ge> {
94		Self::try_primitive("unsigned char").expect("Static primitive type")
95	}
96
97	pub fn float() -> TypeRef<'tu, 'ge> {
98		Self::try_primitive("float").expect("Static primitive type")
99	}
100
101	pub fn double() -> TypeRef<'tu, 'ge> {
102		Self::try_primitive("double").expect("Static primitive type")
103	}
104
105	pub fn int() -> TypeRef<'tu, 'ge> {
106		Self::try_primitive("int").expect("Static primitive type")
107	}
108
109	pub fn int64_t() -> TypeRef<'tu, 'ge> {
110		Self::try_primitive("int64_t").expect("Static primitive type")
111	}
112
113	pub fn uint64_t() -> TypeRef<'tu, 'ge> {
114		Self::try_primitive("uint64_t").expect("Static primitive type")
115	}
116
117	pub fn size_t() -> TypeRef<'tu, 'ge> {
118		Self::try_primitive("size_t").expect("Static primitive type")
119	}
120
121	pub fn array_int(size: Option<usize>) -> TypeRef<'tu, 'ge> {
122		TypeRef::new_array(Self::int(), size)
123	}
124
125	pub fn array_uchar(size: Option<usize>) -> TypeRef<'tu, 'ge> {
126		TypeRef::new_array(Self::uchar(), size)
127	}
128
129	/// `cv::Size_`
130	pub fn cv_size_() -> TypeRef<'tu, 'ge> {
131		TypeRef::new_class(ClassDesc::cv_size_())
132	}
133
134	/// `cv::Size`
135	pub fn cv_size() -> TypeRef<'tu, 'ge> {
136		TypeRef::new_typedef(TypedefDesc::cv_size())
137	}
138
139	/// `cv::Point_`
140	pub fn cv_point_() -> TypeRef<'tu, 'ge> {
141		TypeRef::new_class(ClassDesc::cv_point_())
142	}
143
144	/// `cv::Point`
145	pub fn cv_point() -> TypeRef<'tu, 'ge> {
146		TypeRef::new_typedef(TypedefDesc::cv_point())
147	}
148
149	/// `cv::Point2f`
150	pub fn cv_point2f() -> TypeRef<'tu, 'ge> {
151		TypeRef::new_typedef(TypedefDesc::cv_point2f())
152	}
153
154	/// `cv::Point2d`
155	pub fn cv_point2d() -> TypeRef<'tu, 'ge> {
156		TypeRef::new_typedef(TypedefDesc::cv_point2d())
157	}
158
159	/// `cv::Point3i`
160	pub fn cv_point3i() -> TypeRef<'tu, 'ge> {
161		TypeRef::new_typedef(TypedefDesc::cv_point3i())
162	}
163
164	/// `cv::Point3f`
165	pub fn cv_point3f() -> TypeRef<'tu, 'ge> {
166		TypeRef::new_typedef(TypedefDesc::cv_point3f())
167	}
168
169	/// `cv::Point3d`
170	pub fn cv_point3d() -> TypeRef<'tu, 'ge> {
171		TypeRef::new_typedef(TypedefDesc::cv_point3d())
172	}
173
174	/// `cv::Vec`
175	pub fn cv_vec() -> TypeRef<'tu, 'ge> {
176		TypeRef::new_class(ClassDesc::cv_vec())
177	}
178
179	/// `cv::Vec2f`
180	pub fn cv_vec2f() -> TypeRef<'tu, 'ge> {
181		TypeRef::new_typedef(TypedefDesc::cv_vec2f())
182	}
183
184	/// `cv::Vec2d`
185	pub fn cv_vec2d() -> TypeRef<'tu, 'ge> {
186		TypeRef::new_typedef(TypedefDesc::cv_vec2d())
187	}
188
189	/// `cv::Vec3f`
190	pub fn cv_vec3f() -> TypeRef<'tu, 'ge> {
191		TypeRef::new_typedef(TypedefDesc::cv_vec3f())
192	}
193
194	/// `cv::Vec3d`
195	pub fn cv_vec3d() -> TypeRef<'tu, 'ge> {
196		TypeRef::new_typedef(TypedefDesc::cv_vec3d())
197	}
198
199	/// `cv::Vec4i`
200	pub fn cv_vec4i() -> TypeRef<'tu, 'ge> {
201		TypeRef::new_typedef(TypedefDesc::cv_vec4i())
202	}
203
204	/// `cv::Scalar_`
205	pub fn cv_scalar_() -> TypeRef<'tu, 'ge> {
206		TypeRef::new_class(ClassDesc::cv_scalar_())
207	}
208
209	/// `cv::Scalar`
210	pub fn cv_scalar() -> TypeRef<'tu, 'ge> {
211		TypeRef::new_typedef(TypedefDesc::cv_scalar())
212	}
213
214	/// `cv::_InputArray`
215	pub fn cv_input_array() -> TypeRef<'tu, 'ge> {
216		TypeRef::new_class(ClassDesc::cv_input_array())
217	}
218
219	/// `cv::_OutputArray`
220	pub fn cv_output_array() -> TypeRef<'tu, 'ge> {
221		TypeRef::new_class(ClassDesc::cv_output_array())
222	}
223
224	/// `cv::_InputOutputArray`
225	pub fn cv_input_output_array() -> TypeRef<'tu, 'ge> {
226		TypeRef::new_class(ClassDesc::cv_input_output_array())
227	}
228
229	/// `cv::String`
230	pub fn cv_string() -> TypeRef<'tu, 'ge> {
231		TypeRef::new_class(ClassDesc::cv_string())
232	}
233
234	/// `std::string`
235	pub fn std_string() -> TypeRef<'tu, 'ge> {
236		TypeRef::new_class(ClassDesc::std_string())
237	}
238
239	/// `std::vector<std::vector<double>>`
240	pub fn vector_of_vector_of_double() -> TypeRef<'tu, 'ge> {
241		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRef::new_vector(Vector::new_desc(
242			VectorDesc::new(TypeRefDesc::double()),
243		)))))
244	}
245
246	/// `std::vector<std::vector<int>>`
247	pub fn vector_of_int() -> TypeRef<'tu, 'ge> {
248		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::int())))
249	}
250
251	/// `std::vector<std::vector<int>>`
252	pub fn vector_of_vector_of_int() -> TypeRef<'tu, 'ge> {
253		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(Self::vector_of_int())))
254	}
255
256	/// `std::vector<cv::String>`
257	pub fn vector_of_cv_string() -> TypeRef<'tu, 'ge> {
258		TypeRef::new_vector(VectorDesc::vector_of_cv_string())
259	}
260
261	/// `std::vector<cv::Vec2f>`
262	pub fn vector_of_cv_vec2f() -> TypeRef<'tu, 'ge> {
263		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_vec2f())))
264	}
265
266	/// `std::vector<cv::Vec2d>`
267	pub fn vector_of_cv_vec2d() -> TypeRef<'tu, 'ge> {
268		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_vec2d())))
269	}
270
271	/// `std::vector<cv::Vec3f>`
272	pub fn vector_of_cv_vec3f() -> TypeRef<'tu, 'ge> {
273		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_vec3f())))
274	}
275
276	/// `std::vector<std::vector<cv::Vec2f>>`
277	pub fn vector_of_vector_of_cv_vec2f() -> TypeRef<'tu, 'ge> {
278		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::vector_of_cv_vec2f())))
279	}
280
281	/// `std::vector<std::vector<cv::Vec2d>>`
282	pub fn vector_of_vector_of_cv_vec2d() -> TypeRef<'tu, 'ge> {
283		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::vector_of_cv_vec2d())))
284	}
285
286	/// `std::vector<std::vector<cv::Vec3f>>`
287	pub fn vector_of_vector_of_cv_vec3f() -> TypeRef<'tu, 'ge> {
288		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::vector_of_cv_vec3f())))
289	}
290
291	/// `std::vector<std::vector<cv::Vec3d>>`
292	pub fn vector_of_vector_of_cv_vec3d() -> TypeRef<'tu, 'ge> {
293		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::vector_of_cv_vec3d())))
294	}
295
296	/// `std::vector<cv::Vec3d>`
297	pub fn vector_of_cv_vec3d() -> TypeRef<'tu, 'ge> {
298		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_vec3d())))
299	}
300
301	/// `std::vector<cv::Vec4i>`
302	pub fn vector_of_cv_vec4i() -> TypeRef<'tu, 'ge> {
303		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_vec4i())))
304	}
305
306	/// `std::vector<std::vector<cv::Point>>`
307	pub fn vector_of_vector_of_cv_point() -> TypeRef<'tu, 'ge> {
308		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRef::new_vector(Vector::new_desc(
309			VectorDesc::new(TypeRefDesc::cv_point()),
310		)))))
311	}
312
313	/// `std::vector<cv::Point2f>`
314	pub fn vector_of_cv_point2f() -> TypeRef<'tu, 'ge> {
315		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_point2f())))
316	}
317
318	/// `std::vector<cv::Point2d>`
319	pub fn vector_of_cv_point2d() -> TypeRef<'tu, 'ge> {
320		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_point2d())))
321	}
322
323	/// `std::vector<cv::Point3i>`
324	pub fn vector_of_cv_point3i() -> TypeRef<'tu, 'ge> {
325		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_point3i())))
326	}
327
328	/// `std::vector<std::vector<cv::Point3i>>`
329	pub fn vector_of_vector_of_cv_point3i() -> TypeRef<'tu, 'ge> {
330		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(Self::vector_of_cv_point3i())))
331	}
332
333	/// `std::vector<cv::Point3f>`
334	pub fn vector_of_cv_point3f() -> TypeRef<'tu, 'ge> {
335		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_point3f())))
336	}
337
338	/// `std::vector<std::vector<cv::Point3f>>`
339	pub fn vector_of_vector_of_cv_point3f() -> TypeRef<'tu, 'ge> {
340		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(Self::vector_of_cv_point3f())))
341	}
342
343	/// `std::vector<cv::Point3d>`
344	pub fn vector_of_cv_point3d() -> TypeRef<'tu, 'ge> {
345		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(TypeRefDesc::cv_point3d())))
346	}
347
348	/// `std::vector<std::vector<cv::Point2f>>`
349	pub fn vector_of_vector_of_cv_point2f() -> TypeRef<'tu, 'ge> {
350		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(Self::vector_of_cv_point2f())))
351	}
352
353	/// `std::vector<std::vector<cv::Point2d>>`
354	pub fn vector_of_vector_of_cv_point2d() -> TypeRef<'tu, 'ge> {
355		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(Self::vector_of_cv_point2d())))
356	}
357
358	/// `std::vector<std::vector<cv::Point3d>>`
359	pub fn vector_of_vector_of_cv_point3d() -> TypeRef<'tu, 'ge> {
360		TypeRef::new_vector(Vector::new_desc(VectorDesc::new(Self::vector_of_cv_point3d())))
361	}
362
363	/// `cv::Ptr<float>`
364	pub fn ptr_of_float() -> TypeRef<'tu, 'ge> {
365		TypeRef::new_smartptr(SmartPtr::new_desc(SmartPtrDesc::new(TypeRefDesc::float())))
366	}
367
368	/// `cv::Ptr<cv::Feature2d>`
369	pub fn ptr_of_cv_feature2d() -> TypeRef<'tu, 'ge> {
370		TypeRef::new_smartptr(SmartPtr::new_desc(SmartPtrDesc::new(TypeRefDesc::cv_feature2d())))
371	}
372
373	/// `cv::Feature2D`
374	pub fn cv_feature2d() -> TypeRef<'tu, 'ge> {
375		TypeRef::new_class(ClassDesc::cv_feature2d())
376	}
377
378	/// `cv::dnn::DictValue`
379	pub fn cv_dnn_dict_value() -> TypeRef<'tu, 'ge> {
380		TypeRef::new_class(ClassDesc::cv_dnn_dict_value())
381	}
382
383	/// `cv::Ptr<cv::KeyPoint>`
384	pub fn ptr_of_cv_keypoint() -> TypeRef<'tu, 'ge> {
385		TypeRef::new_smartptr(SmartPtr::new_desc(SmartPtrDesc::new(TypeRefDesc::cv_keypoint())))
386	}
387
388	/// `cv::KeyPoint`
389	pub fn cv_keypoint() -> TypeRef<'tu, 'ge> {
390		TypeRef::new_class(ClassDesc::cv_keypoint())
391	}
392}
393
394pub trait ClangTypeExt<'tu> {
395	fn kind<'ge>(
396		self,
397		type_hint: TypeRefTypeHint,
398		parent_entity: Option<Entity<'tu>>,
399		gen_env: &'ge GeneratorEnv<'tu>,
400	) -> TypeRefKind<'tu, 'ge>;
401
402	fn template_specialization_args<'ge>(self, gen_env: &'ge GeneratorEnv<'tu>) -> Vec<TemplateArg<'tu, 'ge>>;
403}
404
405impl<'tu> ClangTypeExt<'tu> for Type<'tu> {
406	fn kind<'ge>(
407		self,
408		type_hint: TypeRefTypeHint,
409		parent_entity: Option<Entity<'tu>>,
410		gen_env: &'ge GeneratorEnv<'tu>,
411	) -> TypeRefKind<'tu, 'ge> {
412		let kind = self.get_kind();
413		TypeRefKind::try_from_clang_primitive(kind).unwrap_or_else(|| {
414			match kind {
415				TypeKind::Pointer => {
416					let pointee = self.get_pointee_type().expect("No pointee type for pointer");
417					let pointee_typeref = TypeRef::new_ext(pointee, type_hint.recurse_inner(), parent_entity, gen_env);
418					let pointee_kind = pointee_typeref.kind();
419					if pointee_kind.is_function() {
420						pointee_kind.into_owned()
421					} else if matches!(pointee_typeref.type_hint(), TypeRefTypeHint::Slice) {
422						TypeRefKind::Array(pointee_typeref, None)
423					} else {
424						TypeRefKind::Pointer(pointee_typeref)
425					}
426				}
427
428				TypeKind::LValueReference => TypeRefKind::Reference(TypeRef::new_ext(
429					self.get_pointee_type().expect("No pointee type for reference"),
430					type_hint.recurse_inner(),
431					parent_entity,
432					gen_env,
433				)),
434
435				TypeKind::RValueReference => TypeRefKind::RValueReference(TypeRef::new_ext(
436					self.get_pointee_type().expect("No pointee type for reference"),
437					type_hint,
438					parent_entity,
439					gen_env,
440				)),
441
442				TypeKind::Elaborated => {
443					let out = self
444						.get_elaborated_type()
445						.expect("Can't get elaborated type")
446						.kind(type_hint, parent_entity, gen_env);
447					if matches!(out, TypeRefKind::Class(..)) {
448						let mut elaborate_name = self.get_display_name();
449						elaborate_name.replace_in_place("const ", "");
450						if elaborate_name.starts_with("std::") {
451							if let Some(decl) = self.get_declaration().map(|decl| decl.get_definition().unwrap_or(decl)) {
452								return TypeRefKind::Class(Class::new_ext(decl, elaborate_name, gen_env));
453							}
454						}
455					}
456					out
457				}
458
459				TypeKind::Record | TypeKind::Unexposed => {
460					if let Some(decl) = self.get_declaration().map(|decl| decl.get_definition().unwrap_or(decl)) {
461						let cpp_refname = decl.cpp_name(CppNameStyle::Reference);
462						if cpp_refname.starts_with("std::") && cpp_refname.contains("::vector") {
463							TypeRefKind::StdVector(Vector::new(self, gen_env))
464						} else if cpp_refname.starts_with("std::") && cpp_refname.contains("::tuple") {
465							TypeRefKind::StdTuple(Tuple::new(self, gen_env))
466						} else if cpp_refname.starts_with("std::") && cpp_refname.contains("::pair") {
467							TypeRefKind::StdTuple(Tuple::pair(self, gen_env))
468						} else if cpp_refname.starts_with("cv::Ptr")
469							&& matches!(decl.get_kind(), EntityKind::StructDecl | EntityKind::ClassDecl)
470						{
471							TypeRefKind::SmartPtr(SmartPtr::new(decl, gen_env))
472						} else {
473							TypeRefKind::Class(Class::new(decl, gen_env))
474						}
475					} else {
476						let mut generic_type = self.get_display_name();
477						// workaround for clang6, FunctionPrototype is seen as Unexposed
478						if generic_type.contains('(') && generic_type.contains(')') {
479							if let Some(parent_entity) = parent_entity {
480								TypeRefKind::Function(Function::new(self, parent_entity, gen_env))
481							} else {
482								TypeRefKind::Ignored
483							}
484						} else {
485							generic_type.replace_in_place("const ", "");
486							if let Some(&(rust, cpp)) = settings::PRIMITIVE_TYPEDEFS.get(generic_type.as_str()) {
487								// uint64_t in gapi module ends here for some reason
488								TypeRefKind::Primitive(rust, cpp)
489							} else {
490								TypeRefKind::Generic(generic_type)
491							}
492						}
493					}
494				}
495
496				TypeKind::Typedef => {
497					let decl = self
498						.get_declaration()
499						.map(|decl| decl.get_definition().unwrap_or(decl))
500						.expect("Can't get typedef declaration");
501					let decl_name = decl.cpp_name(CppNameStyle::Reference);
502					if let Some(&(rust, cpp)) = settings::PRIMITIVE_TYPEDEFS.get(decl_name.as_ref()) {
503						TypeRefKind::Primitive(rust, cpp)
504					} else if decl.is_system() {
505						if decl_name.starts_with("std::") && decl_name.ends_with("::string") {
506							TypeRefKind::Class(Class::new(decl, gen_env))
507						} else {
508							TypeRefKind::Ignored
509						}
510					} else {
511						match Typedef::try_new(decl, gen_env) {
512							NewTypedefResult::Typedef(tdef) => TypeRefKind::Typedef(tdef),
513							NewTypedefResult::Class(cls) => TypeRefKind::Class(cls),
514							NewTypedefResult::Enum(enm) => TypeRefKind::Enum(enm),
515						}
516					}
517				}
518
519				TypeKind::Enum => {
520					let decl = self
521						.get_declaration()
522						.map(|decl| decl.get_definition().unwrap_or(decl))
523						.expect("Can't get typedef declaration");
524					TypeRefKind::Enum(Enum::new(decl, gen_env))
525				}
526
527				TypeKind::FunctionPrototype => {
528					if let Some(parent) = parent_entity {
529						TypeRefKind::Function(Function::new(self, parent, gen_env))
530					} else {
531						TypeRefKind::Ignored
532					}
533				}
534
535				TypeKind::ConstantArray | TypeKind::IncompleteArray => {
536					let mut size = self.get_size();
537					if size.is_none() {
538						if let TypeRefTypeHint::AddArrayLength(force_size) = type_hint {
539							size = Some(force_size);
540						}
541					}
542					TypeRefKind::Array(
543						TypeRef::new_ext(
544							self.get_element_type().expect("Can't get array element type"),
545							type_hint,
546							None,
547							gen_env,
548						),
549						size,
550					)
551				}
552
553				TypeKind::MemberPointer | TypeKind::DependentSizedArray => TypeRefKind::Ignored,
554
555				_ => unreachable!("Can't decide kind: {:#?}", self),
556			}
557		})
558	}
559
560	fn template_specialization_args<'ge>(self, gen_env: &'ge GeneratorEnv<'tu>) -> Vec<TemplateArg<'tu, 'ge>> {
561		match self.get_kind() {
562			TypeKind::Typedef => {
563				vec![]
564			}
565			_ => {
566				let args = self.get_template_argument_types().unwrap_or_default();
567				// there is no way to extract constant generic arguments (e.g. Vec<double, 3>) via libclang
568				// so we have to apply some hacks
569				static TYPE_EXTRACT: LazyLock<Regex> = LazyLock::new(|| {
570					Regex::new(r"^.+<\s*(.+?)\s*(?:,\s*(.+?)\s*)?(?:,\s*(.+?)\s*)?(?:,\s*(.+?)\s*)?>$")
571						.expect("Can't compile static regex")
572				});
573				// getting declaration resolves constants so `Vec<int, nFeatures>` becomes `Vec<int, 18>`
574				let display_name = self
575					.get_declaration()
576					.and_then(|d| d.get_display_name())
577					.unwrap_or_else(|| self.get_display_name());
578				let generic_args: LazyCell<Option<Captures>, _> = LazyCell::new(|| TYPE_EXTRACT.captures(display_name.as_bytes()));
579				args
580					.into_iter()
581					.enumerate()
582					.map(|(i, type_ref)| {
583						if let Some(type_ref) = type_ref {
584							TemplateArg::Typename(TypeRef::new(type_ref, gen_env))
585						} else {
586							if let Some(generic_args) = &*generic_args {
587								generic_args
588									.get(i + 1)
589									.map(|m| TemplateArg::Constant(String::from_utf8_lossy(m.as_bytes()).into_owned()))
590							} else {
591								None
592							}
593							.unwrap_or(TemplateArg::Unknown)
594						}
595					})
596					.collect::<Vec<_>>()
597			}
598		}
599	}
600}