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