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 let Some(decl) = self.get_declaration() {
451							if elaborate_name.starts_with("std::") {
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() {
461						let cpp_refname = decl.cpp_name(CppNameStyle::Reference);
462						let kind = decl.get_kind();
463						let is_decl = kind == EntityKind::StructDecl || kind == EntityKind::ClassDecl;
464						if cpp_refname.starts_with("std::") && cpp_refname.contains("::vector") {
465							TypeRefKind::StdVector(Vector::new(self, gen_env))
466						} else if cpp_refname.starts_with("std::") && cpp_refname.contains("::tuple") {
467							TypeRefKind::StdTuple(Tuple::new(self, gen_env))
468						} else if cpp_refname.starts_with("std::") && cpp_refname.contains("::pair") {
469							TypeRefKind::StdTuple(Tuple::pair(self, gen_env))
470						} else if is_decl && cpp_refname.starts_with("cv::Ptr") {
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 if let Some(&(rust, cpp)) = settings::PRIMITIVE_TYPEDEFS.get(generic_type.as_str()) {
485							// uint64_t in gapi module ends here for some reason
486							TypeRefKind::Primitive(rust, cpp)
487						} else {
488							generic_type.replace_in_place("const ", "");
489							TypeRefKind::Generic(generic_type)
490						}
491					}
492				}
493
494				TypeKind::Typedef => {
495					let decl = self.get_declaration().expect("Can't get typedef declaration");
496					let decl_name = decl.cpp_name(CppNameStyle::Reference);
497					if let Some(&(rust, cpp)) = settings::PRIMITIVE_TYPEDEFS.get(decl_name.as_ref()) {
498						TypeRefKind::Primitive(rust, cpp)
499					} else if decl.is_system() {
500						if decl_name.starts_with("std::") && decl_name.ends_with("::string") {
501							TypeRefKind::Class(Class::new(decl, gen_env))
502						} else {
503							TypeRefKind::Ignored
504						}
505					} else {
506						match Typedef::try_new(decl, gen_env) {
507							NewTypedefResult::Typedef(tdef) => TypeRefKind::Typedef(tdef),
508							NewTypedefResult::Class(cls) => TypeRefKind::Class(cls),
509							NewTypedefResult::Enum(enm) => TypeRefKind::Enum(enm),
510						}
511					}
512				}
513
514				TypeKind::Enum => TypeRefKind::Enum(Enum::new(
515					self.get_declaration().expect("Can't get enum declaration"),
516					gen_env,
517				)),
518
519				TypeKind::FunctionPrototype => {
520					if let Some(parent) = parent_entity {
521						TypeRefKind::Function(Function::new(self, parent, gen_env))
522					} else {
523						TypeRefKind::Ignored
524					}
525				}
526
527				TypeKind::ConstantArray | TypeKind::IncompleteArray => {
528					let mut size = self.get_size();
529					if size.is_none() {
530						if let TypeRefTypeHint::AddArrayLength(force_size) = type_hint {
531							size = Some(force_size);
532						}
533					}
534					TypeRefKind::Array(
535						TypeRef::new_ext(
536							self.get_element_type().expect("Can't get array element type"),
537							type_hint,
538							None,
539							gen_env,
540						),
541						size,
542					)
543				}
544
545				TypeKind::MemberPointer | TypeKind::DependentSizedArray => TypeRefKind::Ignored,
546
547				_ => unreachable!("Can't decide kind: {:#?}", self),
548			}
549		})
550	}
551
552	fn template_specialization_args<'ge>(self, gen_env: &'ge GeneratorEnv<'tu>) -> Vec<TemplateArg<'tu, 'ge>> {
553		match self.get_kind() {
554			TypeKind::Typedef => {
555				vec![]
556			}
557			_ => {
558				let args = self.get_template_argument_types().unwrap_or_default();
559				// there is no way to extract constant generic arguments (e.g. Vec<double, 3>) via libclang
560				// so we have to apply some hacks
561				static TYPE_EXTRACT: LazyLock<Regex> = LazyLock::new(|| {
562					Regex::new(r"^.+<\s*(.+?)\s*(?:,\s*(.+?)\s*)?(?:,\s*(.+?)\s*)?(?:,\s*(.+?)\s*)?>$")
563						.expect("Can't compile static regex")
564				});
565				// getting declaration resolves constants so `Vec<int, nFeatures>` becomes `Vec<int, 18>`
566				let display_name = self
567					.get_declaration()
568					.and_then(|d| d.get_display_name())
569					.unwrap_or_else(|| self.get_display_name());
570				let generic_args: LazyCell<Option<Captures>, _> = LazyCell::new(|| TYPE_EXTRACT.captures(display_name.as_bytes()));
571				args
572					.into_iter()
573					.enumerate()
574					.map(|(i, type_ref)| {
575						if let Some(type_ref) = type_ref {
576							TemplateArg::Typename(TypeRef::new(type_ref, gen_env))
577						} else {
578							if let Some(generic_args) = &*generic_args {
579								generic_args
580									.get(i + 1)
581									.map(|m| TemplateArg::Constant(String::from_utf8_lossy(m.as_bytes()).into_owned()))
582							} else {
583								None
584							}
585							.unwrap_or(TemplateArg::Unknown)
586						}
587					})
588					.collect::<Vec<_>>()
589			}
590		}
591	}
592}