opencv_binding_generator/
func.rs

1use std::borrow::Cow;
2use std::borrow::Cow::{Borrowed, Owned};
3use std::fmt;
4use std::ops::ControlFlow;
5use std::rc::Rc;
6use std::sync::LazyLock;
7
8use clang::{Availability, Entity, EntityKind, ExceptionSpecification};
9pub use desc::{FuncCppBody, FuncDesc, FuncRustBody, FuncRustExtern};
10pub use func_matcher::{FuncMatchProperties, FuncMatcher, Pred, UsageTracker};
11pub use kind::{FuncKind, OperatorKind, ReturnKind};
12use regex::bytes::Regex;
13use slice_arg_finder::SliceArgFinder;
14
15use crate::debug::{DefinitionLocation, LocationName};
16use crate::element::ExcludeKind;
17use crate::entity::ToEntity;
18use crate::field::FieldDesc;
19use crate::settings::{FuncSpec, ARG_OVERRIDE_SELF};
20use crate::type_ref::{Constness, CppNameStyle, FishStyle, TypeRefDesc, TypeRefTypeHint};
21use crate::writer::rust_native::element::RustElement;
22use crate::writer::rust_native::type_ref::TypeRefExt;
23use crate::{
24	debug, Class, CowMapBorrowedExt, DefaultElement, Element, EntityExt, Field, GeneratedType, GeneratorEnv, IteratorExt,
25	NameDebug, NameStyle, StrExt, StringExt, TypeRef,
26};
27
28mod desc;
29mod func_matcher;
30mod kind;
31mod slice_arg_finder;
32
33#[derive(Clone)]
34pub enum Func<'tu, 'ge> {
35	Clang {
36		entity: Entity<'tu>,
37		rust_custom_leafname: Option<Rc<str>>,
38		gen_env: &'ge GeneratorEnv<'tu>,
39	},
40	Desc(Rc<FuncDesc<'tu, 'ge>>),
41}
42
43impl<'tu, 'ge> Func<'tu, 'ge> {
44	pub fn new(entity: Entity<'tu>, gen_env: &'ge GeneratorEnv<'tu>) -> Self {
45		Self::Clang {
46			entity,
47			rust_custom_leafname: None,
48			gen_env,
49		}
50	}
51
52	pub fn new_ext(entity: Entity<'tu>, rust_custom_leafname: Option<Rc<str>>, gen_env: &'ge GeneratorEnv<'tu>) -> Self {
53		Self::Clang {
54			entity,
55			rust_custom_leafname,
56			gen_env,
57		}
58	}
59
60	pub fn new_desc(desc: FuncDesc<'tu, 'ge>) -> Self {
61		Self::Desc(Rc::new(desc))
62	}
63
64	/// Sets custom rust_leafname for this func, used to e.g. disambiguate function names
65	pub fn set_rust_custom_leafname(&mut self, rust_custom_leafname: Option<Rc<str>>) {
66		match self {
67			Self::Clang {
68				rust_custom_leafname: old_rust_custom_leafname,
69				..
70			} => *old_rust_custom_leafname = rust_custom_leafname,
71			Self::Desc(desc) => {
72				if desc.rust_custom_leafname != rust_custom_leafname {
73					Rc::make_mut(desc).rust_custom_leafname = rust_custom_leafname;
74				}
75			}
76		}
77	}
78
79	pub fn rust_custom_leafname(&self) -> Option<&str> {
80		match self {
81			Self::Clang {
82				rust_custom_leafname, ..
83			} => rust_custom_leafname.as_deref(),
84			Self::Desc(desc) => desc.rust_custom_leafname.as_ref().map(|n| n.as_ref()),
85		}
86	}
87
88	pub fn specialize(self, spec: &FuncSpec) -> Self {
89		let specialized = |type_ref: &TypeRef| -> Option<TypeRef<'static, 'static>> {
90			if type_ref.kind().is_generic() {
91				spec
92					.1
93					.get(type_ref.source().cpp_name(CppNameStyle::Declaration).as_ref())
94					.map(|spec_type| type_ref.map(|_| spec_type().with_inherent_constness(type_ref.constness())))
95			} else {
96				None
97			}
98		};
99
100		let arguments = self
101			.arguments()
102			.iter()
103			.map(|arg| {
104				let arg_type_ref = arg.type_ref();
105				specialized(&arg_type_ref).map_or_else(
106					|| arg.clone(),
107					|type_ref| {
108						Field::new_desc(FieldDesc {
109							cpp_fullname: arg.cpp_name(CppNameStyle::Reference).into(),
110							type_ref,
111							default_value: arg.default_value().map(|v| v.into()),
112						})
113					},
114				)
115			})
116			.collect();
117		let return_type_ref = self.return_type_ref();
118		let kind = match self.kind().into_owned() {
119			FuncKind::GenericFunction => FuncKind::Function,
120			FuncKind::GenericInstanceMethod(cls) => FuncKind::InstanceMethod(cls),
121			kind => kind,
122		};
123		let spec_values = spec.1.values();
124		let mut generic = String::with_capacity(spec_values.len() * 16);
125		for spec in spec_values {
126			generic.extend_sep(", ", &spec().cpp_name(CppNameStyle::Reference));
127		}
128		let mut desc = self.to_desc_with_skip_config(InheritConfig::empty().kind().arguments().return_type_ref());
129		let rust_custom_leafname = Some(if spec.0.contains('+') {
130			spec.0.replacen('+', &self.rust_leafname(FishStyle::No), 1).into()
131		} else {
132			spec.0.into()
133		});
134		let desc_mut = Rc::make_mut(&mut desc);
135		desc_mut.kind = kind;
136		desc_mut.type_hint = FuncTypeHint::Specialized;
137		desc_mut.rust_custom_leafname = rust_custom_leafname;
138		desc_mut.arguments = arguments;
139		desc_mut.return_type_ref = specialized(&return_type_ref).unwrap_or_else(|| return_type_ref.into_owned());
140		desc_mut.cpp_body = FuncCppBody::ManualCall(format!("{{{{name}}}}<{generic}>({{{{args}}}})").into());
141		Self::Desc(desc)
142	}
143
144	pub(crate) fn to_desc_with_skip_config(&self, skip_config: InheritConfig) -> Rc<FuncDesc<'tu, 'ge>> {
145		match self {
146			Func::Clang { .. } => {
147				let kind = if skip_config.kind {
148					FuncKind::Function
149				} else {
150					self.kind().into_owned()
151				};
152				let cpp_name = if skip_config.name {
153					Rc::from("")
154				} else {
155					self.cpp_name(CppNameStyle::Reference).into()
156				};
157				let doc_comment = if skip_config.doc_comment {
158					Rc::from("")
159				} else {
160					self.doc_comment().into()
161				};
162				let arguments: Rc<[Field]> = if skip_config.arguments {
163					Rc::new([])
164				} else {
165					self.arguments().into_owned().into()
166				};
167				let return_type_ref = if skip_config.return_type_ref {
168					TypeRefDesc::void()
169				} else {
170					self.return_type_ref().into_owned()
171				};
172				let def_loc = if skip_config.definition_location {
173					DefinitionLocation::Generated
174				} else {
175					self.file_line_name().location
176				};
177				Rc::new(FuncDesc {
178					kind,
179					type_hint: FuncTypeHint::None,
180					constness: self.constness(),
181					return_kind: self.return_kind(),
182					cpp_name,
183					rust_custom_leafname: self.rust_custom_leafname().map(Rc::from),
184					rust_module: self.rust_module(),
185					doc_comment,
186					def_loc,
187					rust_generic_decls: Rc::new([]),
188					arguments,
189					return_type_ref,
190					cpp_body: FuncCppBody::Auto,
191					rust_body: FuncRustBody::Auto,
192					rust_extern_definition: FuncRustExtern::Auto,
193					cfg_attr: Rc::new(None),
194				})
195			}
196			Func::Desc(desc) => {
197				let kind = if skip_config.kind {
198					FuncKind::Function
199				} else {
200					desc.kind.clone()
201				};
202				let return_type_ref = if skip_config.return_type_ref {
203					TypeRefDesc::void()
204				} else {
205					desc.return_type_ref.clone()
206				};
207				let def_loc = if skip_config.definition_location {
208					DefinitionLocation::Generated
209				} else {
210					desc.def_loc.clone()
211				};
212				let mut desc = Rc::clone(desc);
213				let desc_mut = Rc::make_mut(&mut desc);
214				desc_mut.kind = kind;
215				desc_mut.return_type_ref = return_type_ref;
216				desc_mut.def_loc = def_loc;
217				desc
218			}
219		}
220	}
221
222	pub fn inherit(&mut self, ancestor: &Func<'tu, 'ge>, inherit_config: InheritConfig) {
223		#[inline]
224		fn transfer<'tu, 'ge>(desc: &mut FuncDesc<'tu, 'ge>, ancestor: &Func<'tu, 'ge>, config: InheritConfig) {
225			if config.kind {
226				desc.kind = ancestor.kind().into_owned();
227			}
228			if config.name {
229				desc.cpp_name = ancestor.cpp_name(CppNameStyle::Reference).into();
230			}
231			if config.doc_comment {
232				desc.doc_comment = ancestor.doc_comment().into();
233			}
234			if config.arguments {
235				desc.arguments = ancestor.arguments().into();
236			}
237			if config.return_type_ref {
238				desc.return_type_ref = ancestor.return_type_ref().into_owned();
239			}
240			if config.definition_location {
241				desc.def_loc = ancestor.file_line_name().location;
242			}
243		}
244
245		match self {
246			Func::Clang { .. } => {
247				if inherit_config.any_enabled() {
248					let mut desc = self.to_desc_with_skip_config(inherit_config);
249					transfer(Rc::make_mut(&mut desc), ancestor, inherit_config);
250					*self = Func::Desc(desc);
251				}
252			}
253			Func::Desc(desc) => transfer(Rc::make_mut(desc), ancestor, inherit_config),
254		}
255	}
256
257	pub fn inheriting(mut self, ancestor: &Func<'tu, 'ge>, inherit_config: InheritConfig) -> Self {
258		self.inherit(ancestor, inherit_config);
259		self
260	}
261
262	/// Returns true if function was specialized
263	///
264	/// It's used to add the return type to function identifier because otherwise it will generate identical function names when
265	/// we specialize only on the return type.
266	pub fn is_specialized(&self) -> bool {
267		match self {
268			&Self::Clang { .. } => false,
269			Self::Desc(desc) => matches!(desc.type_hint, FuncTypeHint::Specialized),
270		}
271	}
272
273	pub fn kind(&self) -> Cow<'_, FuncKind<'tu, 'ge>> {
274		match self {
275			&Self::Clang { entity, gen_env, .. } => {
276				const OPERATOR: &str = "operator";
277				Owned(match entity.get_kind() {
278					EntityKind::FunctionDecl => {
279						if let Some(operator) = entity.cpp_name(CppNameStyle::Declaration).strip_prefix(OPERATOR) {
280							let arg_count = entity.get_arguments().map_or(0, |v| v.len());
281							FuncKind::FunctionOperator(OperatorKind::new(operator.trim(), arg_count))
282						} else {
283							FuncKind::Function
284						}
285					}
286					EntityKind::Constructor => FuncKind::Constructor(Class::new(
287						entity.get_semantic_parent().expect("Can't get parent of constructor"),
288						gen_env,
289					)),
290					EntityKind::Method => {
291						let class = Class::new(entity.get_semantic_parent().expect("Can't get parent of method"), gen_env);
292						if entity.is_static_method() {
293							FuncKind::StaticMethod(class)
294						} else if let Some(operator) = entity.cpp_name(CppNameStyle::Declaration).strip_prefix(OPERATOR) {
295							let arg_count = entity.get_arguments().map_or(0, |v| v.len());
296							FuncKind::InstanceOperator(class, OperatorKind::new(operator.trim(), arg_count))
297						} else {
298							FuncKind::InstanceMethod(class)
299						}
300					}
301					EntityKind::ConversionFunction => FuncKind::ConversionMethod(Class::new(
302						entity.get_semantic_parent().expect("Can't get parent of method"),
303						gen_env,
304					)),
305					EntityKind::FunctionTemplate => match entity.get_template_kind() {
306						Some(EntityKind::Method) => FuncKind::GenericInstanceMethod(Class::new(
307							entity.get_semantic_parent().expect("Can't get parent of generic method"),
308							gen_env,
309						)),
310						_ => FuncKind::GenericFunction,
311					},
312					_ => unreachable!("Unknown function entity: {:#?}", entity),
313				})
314			}
315			Self::Desc(desc) => Borrowed(&desc.kind),
316		}
317	}
318
319	pub fn constness(&self) -> Constness {
320		match self {
321			&Self::Clang { entity, .. } => Constness::from_is_const(entity.is_const_method()),
322			Self::Desc(desc) => desc.constness,
323		}
324	}
325
326	pub fn is_abstract(&self) -> bool {
327		match self {
328			Self::Clang { entity, .. } => entity.is_pure_virtual_method(),
329			Self::Desc(_) => false,
330		}
331	}
332
333	pub fn is_generic(&self) -> bool {
334		match self {
335			Func::Clang { entity, .. } => {
336				matches!(entity.get_kind(), EntityKind::FunctionTemplate)
337			}
338			Func::Desc(desc) => match desc.kind {
339				FuncKind::GenericFunction | FuncKind::GenericInstanceMethod(..) => true,
340				FuncKind::Function
341				| FuncKind::Constructor(..)
342				| FuncKind::InstanceMethod(..)
343				| FuncKind::StaticMethod(..)
344				| FuncKind::FieldAccessor(..)
345				| FuncKind::ConversionMethod(..)
346				| FuncKind::FunctionOperator(..)
347				| FuncKind::InstanceOperator(..) => false,
348			},
349		}
350	}
351
352	pub fn return_kind(&self) -> ReturnKind {
353		match self {
354			Self::Clang { entity, gen_env, .. } => {
355				let is_infallible = matches!(
356					entity.get_exception_specification(),
357					Some(ExceptionSpecification::BasicNoexcept) | Some(ExceptionSpecification::Unevaluated)
358				) || gen_env.settings.force_infallible.get(&mut self.matcher()).is_some();
359				if is_infallible {
360					let return_type_ref = self.return_type_ref();
361					if return_type_ref.kind().return_as_naked(return_type_ref.type_hint()) {
362						ReturnKind::InfallibleNaked
363					} else {
364						ReturnKind::InfallibleViaArg
365					}
366				} else {
367					ReturnKind::Fallible
368				}
369			}
370			Self::Desc(desc) => desc.return_kind,
371		}
372	}
373
374	pub fn safety(&self) -> Safety {
375		let out = match self {
376			Func::Clang { gen_env, .. } => Safety::from_is_unsafe(gen_env.settings.func_unsafe.get(&mut self.matcher()).is_some()),
377			Func::Desc(_) => Safety::Safe,
378		};
379		out.or_is_unsafe(|| {
380			self.arguments().iter().any(|a| {
381				let type_ref = a.type_ref();
382				type_ref.kind().is_rust_by_ptr(type_ref.type_hint()) && !a.is_user_data()
383			})
384		})
385	}
386
387	pub fn is_default_constructor(&self) -> bool {
388		match self {
389			&Self::Clang { entity, .. } => entity.is_default_constructor() && !self.has_arguments(),
390			Self::Desc(_) => false,
391		}
392	}
393
394	pub fn is_clone(&self) -> bool {
395		if self.cpp_name(CppNameStyle::Declaration) == "clone" {
396			self
397				.kind()
398				.as_instance_method()
399				.is_some_and(|c| !self.has_arguments() && self.return_type_ref().kind().as_class().is_some_and(|r| r.as_ref() == c))
400		} else {
401			false
402		}
403	}
404
405	pub fn is_no_discard(&self) -> bool {
406		match self {
407			&Self::Clang { entity, gen_env, .. } => gen_env.get_export_config(entity).is_some_and(|c| c.no_discard),
408			Self::Desc(_) => false,
409		}
410	}
411
412	pub fn return_type_ref(&self) -> Cow<'_, TypeRef<'tu, 'ge>> {
413		match self {
414			&Self::Clang { entity, gen_env, .. } => {
415				let mut out = match self.kind().as_ref() {
416					FuncKind::Constructor(cls) => cls.type_ref(),
417					// `operator =` returns a reference to the `self` value, and it's quite cumbersome to handle correctly
418					FuncKind::InstanceOperator(_, OperatorKind::Set) => TypeRefDesc::void(),
419					FuncKind::Function
420					| FuncKind::InstanceMethod(..)
421					| FuncKind::StaticMethod(..)
422					| FuncKind::FieldAccessor(..)
423					| FuncKind::ConversionMethod(..)
424					| FuncKind::GenericInstanceMethod(..)
425					| FuncKind::GenericFunction
426					| FuncKind::FunctionOperator(..)
427					| FuncKind::InstanceOperator(..) => {
428						let out = TypeRef::new(entity.get_result_type().expect("Can't get return type"), gen_env);
429						out.kind().as_reference().map(|cow| cow.into_owned()).unwrap_or(out)
430					}
431				};
432				if let Some(return_hint) = gen_env.settings.return_override.get(&mut self.matcher()) {
433					out.set_type_hint(return_hint.clone());
434					// if we're returning a BoxedRef then assign its mutability to the mutability of the borrowed argument
435					if let Some((_, borrow_arg_names, _)) = return_hint.as_boxed_as_ref() {
436						let borrow_arg_constness = if borrow_arg_names.contains(&ARG_OVERRIDE_SELF) {
437							self.constness()
438						} else {
439							self
440								.arguments()
441								.iter()
442								.find(|arg| borrow_arg_names.contains(&arg.cpp_name(CppNameStyle::Declaration).as_ref()))
443								.map(|arg| arg.type_ref().constness())
444								.unwrap_or_else(|| panic!("BoxedAsRef refers to the non-existent argument names: {borrow_arg_names:?}"))
445						};
446						out.set_inherent_constness(borrow_arg_constness);
447					}
448				} else if !out.kind().is_char_ptr_string(out.type_hint()) {
449					out.set_type_hint(TypeRefTypeHint::PrimitivePtrAsRaw);
450				}
451				Owned(out)
452			}
453			Self::Desc(desc) => Borrowed(&desc.return_type_ref),
454		}
455	}
456
457	pub fn has_arguments(&self) -> bool {
458		self.num_arguments() > 0
459	}
460
461	pub fn num_arguments(&self) -> usize {
462		match self {
463			&Func::Clang { entity, .. } => self.clang_arguments(entity).len(),
464			Func::Desc(desc) => desc.arguments.len(),
465		}
466	}
467
468	fn clang_arguments(&self, entity: Entity<'tu>) -> Vec<Entity<'tu>> {
469		match self.kind().as_ref() {
470			FuncKind::GenericFunction | FuncKind::GenericInstanceMethod(..) => {
471				let mut out = Vec::with_capacity(8);
472				let _ = entity.walk_children_while(|child| {
473					if child.get_kind() == EntityKind::ParmDecl {
474						out.push(child);
475					}
476					ControlFlow::Continue(())
477				});
478				out
479			}
480			_ => entity.get_arguments().expect("Can't get arguments"),
481		}
482	}
483
484	pub fn arguments(&self) -> Cow<'_, [Field<'tu, 'ge>]> {
485		match self {
486			&Self::Clang { entity, gen_env, .. } => {
487				let arg_overrides = gen_env.settings.arg_override.get(&mut self.matcher());
488				let arguments = self.clang_arguments(entity);
489				let mut slice_arg_finder = SliceArgFinder::with_capacity(arguments.len());
490				let mut out = arguments
491					.into_iter()
492					.enumerate()
493					.map(|(idx, a)| {
494						if let Some(func_arg_override) = arg_overrides {
495							if let Some(type_hint) = a.get_name().and_then(|arg_name| func_arg_override.get(arg_name.as_str())) {
496								return Field::new_ext(a, type_hint.clone(), gen_env);
497							}
498						}
499						let out = Field::new(a, gen_env);
500						slice_arg_finder.feed(idx, &out);
501						out
502					})
503					.collect::<Vec<_>>();
504				for (slice_arg_indices, slice_len_arg_idx) in slice_arg_finder.finish() {
505					let mut slice_arg_names = Vec::with_capacity(slice_arg_indices.len());
506					for &slice_arg_idx in &slice_arg_indices {
507						let slice_arg = &mut out[slice_arg_idx];
508						slice_arg_names.push(slice_arg.rust_name(NameStyle::ref_()).into_owned());
509						slice_arg.set_type_ref_type_hint(TypeRefTypeHint::Slice);
510					}
511					let slice_len_arg = &mut out[slice_len_arg_idx];
512					let divisor = if slice_len_arg.cpp_name(CppNameStyle::Declaration).contains("pair") {
513						2
514					} else {
515						1
516					};
517					slice_len_arg.set_type_ref_type_hint(TypeRefTypeHint::LenForSlice(slice_arg_names.into(), divisor));
518				}
519				Owned(out)
520			}
521			Self::Desc(desc) => Borrowed(desc.arguments.as_ref()),
522		}
523	}
524
525	pub fn generated_types(&self) -> Vec<GeneratedType<'tu, 'ge>> {
526		self
527			.arguments()
528			.iter()
529			.map(|a| a.type_ref())
530			.filter(|t| !t.exclude_kind().is_ignored())
531			.flat_map(|t| t.generated_types())
532			.chain(self.return_type_ref().generated_types())
533			.collect()
534	}
535
536	pub fn identifier(&self) -> String {
537		let mut out = if let Some((_, fld)) = self.kind().as_field_accessor() {
538			let mut name = self.cpp_namespace().into_owned();
539			if !name.is_empty() {
540				name.push('_');
541			}
542			let decl_name = fld.cpp_name(CppNameStyle::Declaration);
543			name.reserve(decl_name.len() + 4);
544			name.push_str("prop");
545			let (first_letter, rest) = decl_name.capitalize_first_ascii_letter().expect("Empty decl_name");
546			name.push(first_letter);
547			name.push_str(rest);
548			name
549		} else {
550			self.cpp_name(CppNameStyle::Reference).into_owned()
551		};
552		// add return type to function id for cases when we specialize on the return type, in theory we should be able to apply
553		// this to all of the functions, but it's too much work to rename all those entries in FUNC_RENAME
554		// fixme: introduce FuncMatcher and use this logic for every function and not only specialized ones
555		if self.is_specialized() {
556			out.push('_');
557			out.push_str(&self.return_type_ref().cpp_name(CppNameStyle::Reference));
558		}
559		if self.constness().is_const() {
560			out.push_str("_const");
561		}
562		let args = self.arguments();
563		out.reserve(args.len() * 24);
564		for arg in args.as_ref() {
565			out.push('_');
566			out.push_str(&arg.type_ref().cpp_name_ext(CppNameStyle::Declaration, "", false));
567		}
568		out.cleanup_name();
569		out
570	}
571
572	pub fn matcher(&self) -> FuncMatchProperties<'_> {
573		FuncMatchProperties::new(self, self.cpp_name(CppNameStyle::Reference))
574	}
575
576	pub fn rust_body(&self) -> &FuncRustBody {
577		match self {
578			Self::Clang { .. } => &FuncRustBody::Auto,
579			Self::Desc(desc) => &desc.rust_body,
580		}
581	}
582
583	pub fn rust_extern_definition(&self) -> FuncRustExtern {
584		match self {
585			Self::Clang { .. } => FuncRustExtern::Auto,
586			Self::Desc(desc) => desc.rust_extern_definition,
587		}
588	}
589
590	pub fn cpp_body(&self) -> &FuncCppBody {
591		match self {
592			Self::Clang { .. } => &FuncCppBody::Auto,
593			Self::Desc(desc) => &desc.cpp_body,
594		}
595	}
596
597	pub fn cfg_attrs(&self) -> Option<(&str, &str)> {
598		match self {
599			Self::Clang { gen_env, .. } => gen_env.settings.func_cfg_attr.get(&mut self.matcher()).copied(),
600			Self::Desc(desc) => desc
601				.cfg_attr
602				.as_ref()
603				.as_ref()
604				.map(|(rust, cpp)| (rust.as_str(), cpp.as_str())),
605		}
606	}
607}
608
609impl<'tu> ToEntity<'tu> for &Func<'tu, '_> {
610	fn to_entity(self) -> Option<Entity<'tu>> {
611		match self {
612			Func::Clang { entity, .. } => Some(*entity),
613			Func::Desc(_) => None,
614		}
615	}
616}
617
618impl Element for Func<'_, '_> {
619	fn exclude_kind(&self) -> ExcludeKind {
620		DefaultElement::exclude_kind(self)
621			.with_reference_exclude_kind(|| self.return_type_ref().exclude_kind())
622			.with_is_excluded(|| {
623				let kind = self.kind();
624				let identifier = self.identifier();
625				let is_excluded = match self {
626					Func::Clang { entity, gen_env, .. } => {
627						entity.get_availability() == Availability::Unavailable
628							|| gen_env.settings.func_exclude.contains(identifier.as_str())
629					}
630					Func::Desc(_) => false,
631				};
632				is_excluded
633					|| self.is_generic()
634					|| self.arguments().iter().any(|a| a.type_ref().exclude_kind().is_ignored())
635					|| kind.as_operator().is_some_and(|(_, kind)| match kind {
636						OperatorKind::Unsupported => true,
637						// filter out postfix version of ++ and --: https://en.cppreference.com/w/cpp/language/operator_incdec
638						OperatorKind::Incr | OperatorKind::Decr if self.num_arguments() == 1 => true,
639						_ => false,
640					}) || kind.as_constructor().is_some_and(|cls| cls.is_abstract()) // don't generate constructors of abstract classes
641			})
642	}
643
644	fn is_system(&self) -> bool {
645		match self {
646			&Self::Clang { entity, .. } => DefaultElement::is_system(entity),
647			Self::Desc(_) => false,
648		}
649	}
650
651	fn is_public(&self) -> bool {
652		match self {
653			&Self::Clang { entity, .. } => DefaultElement::is_public(entity),
654			Self::Desc(_) => true,
655		}
656	}
657
658	fn doc_comment(&self) -> Cow<'_, str> {
659		match self {
660			Self::Clang { entity, gen_env, .. } => {
661				// Process `@overload` and `@copybrief` directives if possible by copying the corresponding doccomment
662				let mut out = entity.doc_comment();
663				let line = self.file_line_name().location.as_file().map_or(0, |(_, line)| line);
664				const OVERLOAD: &str = "@overload";
665				if let Some(idx) = out.find(OVERLOAD) {
666					let rep = if let Some(copy) = gen_env.get_func_comment(line, self.cpp_name(CppNameStyle::Reference).as_ref()) {
667						Owned(format!("{copy}\n\n## Overloaded parameters\n"))
668					} else {
669						"This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.".into()
670					};
671					out.to_mut().replace_range(idx..idx + OVERLOAD.len(), &rep);
672				}
673				static COPY_BRIEF: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"@copybrief\s+(\w+)").unwrap());
674				out.to_mut().replace_in_place_regex_cb(&COPY_BRIEF, |comment, caps| {
675					let copy_name = caps.get(1).map(|(s, e)| &comment[s..e]).expect("Impossible");
676					let mut copy_full_name = self.cpp_namespace().into_owned();
677					copy_full_name.extend_sep("::", copy_name);
678					Some(gen_env.get_func_comment(line, &copy_full_name).unwrap_or("").into())
679				});
680				out
681			}
682			Self::Desc(desc) => desc.doc_comment.as_ref().into(),
683		}
684	}
685
686	fn cpp_namespace(&self) -> Cow<'_, str> {
687		match self {
688			&Self::Clang { entity, .. } => DefaultElement::cpp_namespace(entity).into(),
689			Self::Desc(desc) => self.kind().map_borrowed(|kind| match kind {
690				FuncKind::Function | FuncKind::FunctionOperator(_) | FuncKind::GenericFunction => desc.cpp_name.namespace().into(),
691				FuncKind::Constructor(cls)
692				| FuncKind::InstanceMethod(cls)
693				| FuncKind::StaticMethod(cls)
694				| FuncKind::FieldAccessor(cls, _)
695				| FuncKind::ConversionMethod(cls)
696				| FuncKind::InstanceOperator(cls, _)
697				| FuncKind::GenericInstanceMethod(cls) => cls.cpp_name(CppNameStyle::Reference),
698			}),
699		}
700	}
701
702	fn cpp_name(&self, style: CppNameStyle) -> Cow<'_, str> {
703		let decl_name = match self {
704			&Self::Clang { entity, gen_env, .. } => {
705				if matches!(entity.get_kind(), EntityKind::ConversionFunction) {
706					// this is to avoid calling `return_type_ref()` just to get the name of the type otherwise it causes infinite recursion
707					// together with the call `cpp_name(Reference)` from `matcher()`
708					let ret_type = TypeRef::new(entity.get_result_type().expect("Can't get result type"), gen_env);
709					let ret_type = ret_type
710						.kind()
711						.as_reference()
712						.map(|tref| tref.into_owned())
713						.unwrap_or(ret_type);
714					format!("operator {}", ret_type.cpp_name(CppNameStyle::Reference)).into()
715				} else {
716					DefaultElement::cpp_name(self, entity, CppNameStyle::Declaration)
717				}
718			}
719			Self::Desc(desc) => desc.cpp_name.cpp_name_from_fullname(CppNameStyle::Declaration).into(),
720		};
721		match style {
722			CppNameStyle::Declaration => decl_name,
723			CppNameStyle::Reference => DefaultElement::cpp_decl_name_with_namespace(self, &decl_name),
724		}
725	}
726}
727
728impl<'me> NameDebug<'me> for &'me Func<'_, '_> {
729	fn file_line_name(self) -> LocationName<'me> {
730		match self {
731			Func::Clang { entity, .. } => entity.file_line_name(),
732			Func::Desc(desc) => LocationName::new(desc.def_loc.clone(), self.cpp_name(CppNameStyle::Reference)),
733		}
734	}
735
736	fn get_debug(self) -> String
737	where
738		Self: Sized,
739	{
740		if *debug::EMIT_DEBUG {
741			let LocationName { location, name } = self.file_line_name();
742			let render_lanes = self
743				.arguments()
744				.iter()
745				.map(|a| format!("{:?}", a.type_ref().render_lane()))
746				.join(", ");
747			format!(
748				"// {name}({render_lanes}) {location}\n\
749				// {func_match}",
750				func_match = self.matcher().dump()
751			)
752		} else {
753			"".to_string()
754		}
755	}
756}
757
758impl fmt::Debug for Func<'_, '_> {
759	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
760		let mut debug_struct = f.debug_struct(match self {
761			Self::Clang { .. } => "Func::Clang",
762			Self::Desc(_) => "Func::Desc",
763		});
764		self
765			.update_debug_struct(&mut debug_struct)
766			.field("constness", &self.constness())
767			.field("is_specialized", &self.is_specialized())
768			.field("return_kind", &self.return_kind())
769			.field("kind", &self.kind())
770			.field("return_type", &self.return_type_ref())
771			.field("arguments", &self.arguments())
772			.finish()
773	}
774}
775
776#[derive(Clone, Copy, Debug, PartialEq, Eq)]
777pub enum Safety {
778	Safe,
779	Unsafe,
780}
781
782impl Safety {
783	pub fn from_is_unsafe(is_unsafe: bool) -> Safety {
784		if is_unsafe {
785			Self::Unsafe
786		} else {
787			Self::Safe
788		}
789	}
790
791	pub fn is_safe(self) -> bool {
792		match self {
793			Self::Safe => true,
794			Self::Unsafe => false,
795		}
796	}
797
798	/// Returns `Safe` only if both `self` and `other_is_unsafe` are `Safe`, otherwise returns `Unsafe`
799	pub fn or_is_unsafe(self, other_is_unsafe: impl FnOnce() -> bool) -> Safety {
800		match self {
801			Safety::Safe => Self::from_is_unsafe(other_is_unsafe()),
802			Safety::Unsafe => Self::Unsafe,
803		}
804	}
805
806	/// Returns `""` or `"unsafe "`, for usage as function declaration specifier
807	pub fn rust_func_safety_qual(self) -> &'static str {
808		match self {
809			Safety::Safe => "",
810			Safety::Unsafe => "unsafe ",
811		}
812	}
813}
814
815#[derive(Copy, Clone, Debug, PartialEq, Eq)]
816pub enum FuncTypeHint {
817	None,
818	Specialized,
819}
820
821#[derive(Debug, Clone, Copy)]
822pub struct InheritConfig {
823	pub kind: bool,
824	pub name: bool,
825	pub doc_comment: bool,
826	pub arguments: bool,
827	pub return_type_ref: bool,
828	pub definition_location: bool,
829}
830
831impl InheritConfig {
832	pub const fn empty() -> Self {
833		Self {
834			kind: false,
835			name: false,
836			doc_comment: false,
837			arguments: false,
838			return_type_ref: false,
839			definition_location: false,
840		}
841	}
842
843	pub fn kind(mut self) -> Self {
844		self.kind = true;
845		self
846	}
847
848	pub fn with_name(mut self) -> Self {
849		self.name = true;
850		self
851	}
852
853	pub fn doc_comment(mut self) -> Self {
854		self.doc_comment = true;
855		self
856	}
857
858	pub fn arguments(mut self) -> Self {
859		self.arguments = true;
860		self
861	}
862
863	pub fn return_type_ref(mut self) -> Self {
864		self.return_type_ref = true;
865		self
866	}
867
868	pub fn definition_location(mut self) -> Self {
869		self.definition_location = true;
870		self
871	}
872
873	pub fn any_enabled(self) -> bool {
874		self.kind || self.name || self.arguments || self.doc_comment || self.return_type_ref || self.definition_location
875	}
876}