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::{ARG_OVERRIDE_SELF, FuncSpec};
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 Class, CowMapBorrowedExt, DefaultElement, Element, EntityExt, Field, GeneratedType, GeneratorEnv, IteratorExt, NameDebug,
25 NameStyle, StrExt, StringExt, TypeRef, debug,
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 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 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 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 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 let arg_name = a.get_name();
495 if let Some(func_arg_override) = arg_overrides
496 && let Some(type_hint) = arg_name.as_deref().and_then(|arg_name| func_arg_override.get(arg_name))
497 {
498 return Field::new_ext(a, type_hint.clone(), gen_env);
499 }
500 let mut arg = Field::new(a, gen_env);
501 if let Some(arg_name) = arg_name.as_deref() {
502 update_path_argument(&mut arg, arg_name);
503 }
504 slice_arg_finder.feed(idx, &arg);
505 arg
506 })
507 .collect::<Vec<_>>();
508 update_slice_arguments(&mut out, slice_arg_finder);
509 Owned(out)
510 }
511 Self::Desc(desc) => Borrowed(desc.arguments.as_ref()),
512 }
513 }
514
515 pub fn generated_types(&self) -> Vec<GeneratedType<'tu, 'ge>> {
516 self
517 .arguments()
518 .iter()
519 .map(|a| a.type_ref())
520 .filter(|t| !t.exclude_kind().is_ignored())
521 .flat_map(|t| t.generated_types())
522 .chain(self.return_type_ref().generated_types())
523 .collect()
524 }
525
526 pub fn identifier(&self) -> String {
527 let mut out = if let Some((_, fld)) = self.kind().as_field_accessor() {
528 let mut name = self.cpp_namespace().into_owned();
529 if !name.is_empty() {
530 name.push('_');
531 }
532 let decl_name = fld.cpp_name(CppNameStyle::Declaration);
533 name.reserve(decl_name.len() + 4);
534 name.push_str("prop");
535 let (first_letter, rest) = decl_name.capitalize_first_ascii_letter().expect("Empty decl_name");
536 name.push(first_letter);
537 name.push_str(rest);
538 name
539 } else {
540 self.cpp_name(CppNameStyle::Reference).into_owned()
541 };
542 if self.is_specialized() {
546 out.push('_');
547 out.push_str(&self.return_type_ref().cpp_name(CppNameStyle::Reference));
548 }
549 if self.constness().is_const() {
550 out.push_str("_const");
551 }
552 let args = self.arguments();
553 out.reserve(args.len() * 24);
554 for arg in args.as_ref() {
555 out.push('_');
556 out.push_str(&arg.type_ref().cpp_name_ext(CppNameStyle::Declaration, "", false));
557 }
558 out.cleanup_name();
559 out
560 }
561
562 pub fn matcher(&self) -> FuncMatchProperties<'_> {
563 FuncMatchProperties::new(self, self.cpp_name(CppNameStyle::Reference))
564 }
565
566 pub fn rust_body(&self) -> &FuncRustBody {
567 match self {
568 Self::Clang { .. } => &FuncRustBody::Auto,
569 Self::Desc(desc) => &desc.rust_body,
570 }
571 }
572
573 pub fn rust_extern_definition(&self) -> FuncRustExtern {
574 match self {
575 Self::Clang { .. } => FuncRustExtern::Auto,
576 Self::Desc(desc) => desc.rust_extern_definition,
577 }
578 }
579
580 pub fn cpp_body(&self) -> &FuncCppBody {
581 match self {
582 Self::Clang { .. } => &FuncCppBody::Auto,
583 Self::Desc(desc) => &desc.cpp_body,
584 }
585 }
586
587 pub fn cfg_attrs(&self) -> Option<(&str, &str)> {
588 match self {
589 Self::Clang { gen_env, .. } => gen_env.settings.func_cfg_attr.get(&mut self.matcher()).copied(),
590 Self::Desc(desc) => desc
591 .cfg_attr
592 .as_ref()
593 .as_ref()
594 .map(|(rust, cpp)| (rust.as_str(), cpp.as_str())),
595 }
596 }
597}
598
599impl<'tu> ToEntity<'tu> for &Func<'tu, '_> {
600 fn to_entity(self) -> Option<Entity<'tu>> {
601 match self {
602 Func::Clang { entity, .. } => Some(*entity),
603 Func::Desc(_) => None,
604 }
605 }
606}
607
608impl Element for Func<'_, '_> {
609 fn exclude_kind(&self) -> ExcludeKind {
610 DefaultElement::exclude_kind(self)
611 .with_reference_exclude_kind(|| self.return_type_ref().exclude_kind())
612 .with_is_excluded(|| {
613 let kind = self.kind();
614 let identifier = self.identifier();
615 let is_excluded = match self {
616 Func::Clang { entity, gen_env, .. } => {
617 entity.get_availability() == Availability::Unavailable
618 || gen_env.settings.func_exclude.contains(identifier.as_str())
619 }
620 Func::Desc(_) => false,
621 };
622 is_excluded
623 || self.is_generic()
624 || self.arguments().iter().any(|a| a.type_ref().exclude_kind().is_ignored())
625 || kind.as_operator().is_some_and(|(_, kind)| match kind {
626 OperatorKind::Unsupported => true,
627 OperatorKind::Incr | OperatorKind::Decr if self.num_arguments() == 1 => true,
629 _ => false,
630 }) || kind.as_constructor().is_some_and(|cls| cls.is_abstract()) })
632 }
633
634 fn is_system(&self) -> bool {
635 match self {
636 &Self::Clang { entity, .. } => DefaultElement::is_system(entity),
637 Self::Desc(_) => false,
638 }
639 }
640
641 fn is_public(&self) -> bool {
642 match self {
643 &Self::Clang { entity, .. } => DefaultElement::is_public(entity),
644 Self::Desc(_) => true,
645 }
646 }
647
648 fn doc_comment(&self) -> Cow<'_, str> {
649 match self {
650 Self::Clang { entity, gen_env, .. } => {
651 let mut out = entity.doc_comment();
653 let line = self.file_line_name().location.as_file().map_or(0, |(_, line)| line);
654 const OVERLOAD: &str = "@overload";
655 if let Some(idx) = out.find(OVERLOAD) {
656 let rep = if let Some(copy) = gen_env.get_func_comment(line, self.cpp_name(CppNameStyle::Reference).as_ref()) {
657 Owned(format!("{copy}\n\n## Overloaded parameters\n"))
658 } else {
659 "This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.".into()
660 };
661 out.to_mut().replace_range(idx..idx + OVERLOAD.len(), &rep);
662 }
663 static COPY_BRIEF: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"@copybrief\s+(\w+)").unwrap());
664 out.to_mut().replace_in_place_regex_cb(©_BRIEF, |comment, caps| {
665 let copy_name = caps.get(1).map(|(s, e)| &comment[s..e]).expect("Impossible");
666 let mut copy_full_name = self.cpp_namespace().into_owned();
667 copy_full_name.extend_sep("::", copy_name);
668 Some(gen_env.get_func_comment(line, ©_full_name).unwrap_or("").into())
669 });
670 out
671 }
672 Self::Desc(desc) => desc.doc_comment.as_ref().into(),
673 }
674 }
675
676 fn cpp_namespace(&self) -> Cow<'_, str> {
677 match self {
678 &Self::Clang { entity, .. } => DefaultElement::cpp_namespace(entity).into(),
679 Self::Desc(desc) => self.kind().map_borrowed(|kind| match kind {
680 FuncKind::Function | FuncKind::FunctionOperator(_) | FuncKind::GenericFunction => desc.cpp_name.namespace().into(),
681 FuncKind::Constructor(cls)
682 | FuncKind::InstanceMethod(cls)
683 | FuncKind::StaticMethod(cls)
684 | FuncKind::FieldAccessor(cls, _)
685 | FuncKind::ConversionMethod(cls)
686 | FuncKind::InstanceOperator(cls, _)
687 | FuncKind::GenericInstanceMethod(cls) => cls.cpp_name(CppNameStyle::Reference),
688 }),
689 }
690 }
691
692 fn cpp_name(&self, style: CppNameStyle) -> Cow<'_, str> {
693 let decl_name = match self {
694 &Self::Clang { entity, gen_env, .. } => {
695 if matches!(entity.get_kind(), EntityKind::ConversionFunction) {
696 let ret_type = TypeRef::new(entity.get_result_type().expect("Can't get result type"), gen_env);
699 let ret_type = ret_type
700 .kind()
701 .as_reference()
702 .map(|tref| tref.into_owned())
703 .unwrap_or(ret_type);
704 format!("operator {}", ret_type.cpp_name(CppNameStyle::Reference)).into()
705 } else {
706 DefaultElement::cpp_name(self, entity, CppNameStyle::Declaration)
707 }
708 }
709 Self::Desc(desc) => desc.cpp_name.cpp_name_from_fullname(CppNameStyle::Declaration).into(),
710 };
711 match style {
712 CppNameStyle::Declaration => decl_name,
713 CppNameStyle::Reference => DefaultElement::cpp_decl_name_with_namespace(self, &decl_name),
714 }
715 }
716}
717
718impl<'me> NameDebug<'me> for &'me Func<'_, '_> {
719 fn file_line_name(self) -> LocationName<'me> {
720 match self {
721 Func::Clang { entity, .. } => entity.file_line_name(),
722 Func::Desc(desc) => LocationName::new(desc.def_loc.clone(), self.cpp_name(CppNameStyle::Reference)),
723 }
724 }
725
726 fn get_debug(self) -> String
727 where
728 Self: Sized,
729 {
730 if debug::enabled() {
731 let LocationName { location, name } = self.file_line_name();
732 let render_lanes = self
733 .arguments()
734 .iter()
735 .map(|a| format!("{:?}", a.type_ref().render_lane()))
736 .join(", ");
737 format!(
738 "// {name}({render_lanes}) {location}\n\
739 // {func_match}",
740 func_match = self.matcher().dump()
741 )
742 } else {
743 "".to_string()
744 }
745 }
746}
747
748impl fmt::Debug for Func<'_, '_> {
749 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
750 let mut debug_struct = f.debug_struct(match self {
751 Self::Clang { .. } => "Func::Clang",
752 Self::Desc(_) => "Func::Desc",
753 });
754 self
755 .update_debug_struct(&mut debug_struct)
756 .field("constness", &self.constness())
757 .field("is_specialized", &self.is_specialized())
758 .field("return_kind", &self.return_kind())
759 .field("kind", &self.kind())
760 .field("return_type", &self.return_type_ref())
761 .field("arguments", &self.arguments())
762 .finish()
763 }
764}
765
766#[derive(Clone, Copy, Debug, PartialEq, Eq)]
767pub enum Safety {
768 Safe,
769 Unsafe,
770}
771
772impl Safety {
773 pub fn from_is_unsafe(is_unsafe: bool) -> Safety {
774 if is_unsafe {
775 Self::Unsafe
776 } else {
777 Self::Safe
778 }
779 }
780
781 pub fn is_safe(self) -> bool {
782 match self {
783 Self::Safe => true,
784 Self::Unsafe => false,
785 }
786 }
787
788 pub fn or_is_unsafe(self, other_is_unsafe: impl FnOnce() -> bool) -> Safety {
790 match self {
791 Safety::Safe => Self::from_is_unsafe(other_is_unsafe()),
792 Safety::Unsafe => Self::Unsafe,
793 }
794 }
795
796 pub fn rust_func_safety_qual(self) -> &'static str {
798 match self {
799 Safety::Safe => "",
800 Safety::Unsafe => "unsafe ",
801 }
802 }
803}
804
805#[derive(Copy, Clone, Debug, PartialEq, Eq)]
806pub enum FuncTypeHint {
807 None,
808 Specialized,
809}
810
811#[derive(Debug, Clone, Copy)]
812pub struct InheritConfig {
813 pub kind: bool,
814 pub name: bool,
815 pub doc_comment: bool,
816 pub arguments: bool,
817 pub return_type_ref: bool,
818 pub definition_location: bool,
819}
820
821impl InheritConfig {
822 pub const fn empty() -> Self {
823 Self {
824 kind: false,
825 name: false,
826 doc_comment: false,
827 arguments: false,
828 return_type_ref: false,
829 definition_location: false,
830 }
831 }
832
833 pub fn kind(mut self) -> Self {
834 self.kind = true;
835 self
836 }
837
838 pub fn with_name(mut self) -> Self {
839 self.name = true;
840 self
841 }
842
843 pub fn doc_comment(mut self) -> Self {
844 self.doc_comment = true;
845 self
846 }
847
848 pub fn arguments(mut self) -> Self {
849 self.arguments = true;
850 self
851 }
852
853 pub fn return_type_ref(mut self) -> Self {
854 self.return_type_ref = true;
855 self
856 }
857
858 pub fn definition_location(mut self) -> Self {
859 self.definition_location = true;
860 self
861 }
862
863 pub fn any_enabled(self) -> bool {
864 self.kind || self.name || self.arguments || self.doc_comment || self.return_type_ref || self.definition_location
865 }
866}
867
868fn update_path_argument(field: &mut Field, arg_name: &str) {
871 const CHECK_SUFFIXES: [&str; 5] = ["file", "filename", "file_name", "path", "pathorname"];
872 const CHECK_PREFIXES: [&str; 2] = ["pathto", "path_to"];
873
874 let len = arg_name.len();
875 let arg_name_matched = CHECK_SUFFIXES
876 .into_iter()
877 .filter(|suf| suf.len() <= len)
878 .flat_map(|suf| {
879 arg_name
880 .get(len - suf.len()..)
881 .filter(|suf_check| suf_check.eq_ignore_ascii_case(suf))
882 })
883 .chain(CHECK_PREFIXES.into_iter().flat_map(|pref| {
884 arg_name
885 .get(..pref.len())
886 .filter(|pref_check| pref_check.eq_ignore_ascii_case(pref))
887 }))
888 .next()
889 .is_some();
890 if arg_name_matched {
891 field.set_type_ref_type_hint(TypeRefTypeHint::StringAsPath);
892 return;
893 }
894
895 if arg_name == "filenames" || arg_name == "paths" {
896 }
898}
899
900fn update_slice_arguments(arguments: &mut [Field], slice_arg_finder: SliceArgFinder) {
901 for (slice_arg_indices, slice_len_arg_idx) in slice_arg_finder.finish() {
902 let mut slice_arg_names = Vec::with_capacity(slice_arg_indices.len());
903 for &slice_arg_idx in &slice_arg_indices {
904 let slice_arg = &mut arguments[slice_arg_idx];
905 slice_arg_names.push(slice_arg.rust_name(NameStyle::ref_()).into_owned());
906 slice_arg.set_type_ref_type_hint(TypeRefTypeHint::Slice);
907 }
908 let slice_len_arg = &mut arguments[slice_len_arg_idx];
909 let divisor = if slice_len_arg.cpp_name(CppNameStyle::Declaration).contains("pair") {
910 2
911 } else {
912 1
913 };
914 slice_len_arg.set_type_ref_type_hint(TypeRefTypeHint::LenForSlice(slice_arg_names.into(), divisor));
915 }
916}