1use std::borrow::Cow;
2use std::collections::HashSet;
3use std::hash::{Hash, Hasher};
4use std::ops::ControlFlow;
5use std::rc::Rc;
6use std::{fmt, iter};
7
8use clang::{Accessibility, Entity, EntityKind};
9pub use desc::ClassDesc;
10
11use crate::debug::{DefinitionLocation, LocationName};
12use crate::element::ExcludeKind;
13use crate::entity::{ControlFlowExt, ToEntity};
14use crate::field::FieldDesc;
15use crate::func::{FuncCppBody, FuncDesc, FuncKind, ReturnKind};
16use crate::settings::PropertyReadWrite;
17use crate::type_ref::{Constness, CppNameStyle, StrEnc, StrType, TypeRef, TypeRefDesc, TypeRefTypeHint};
18use crate::writer::rust_native::element::RustElement;
19use crate::{
20 ClassKindOverride, Const, DefaultElement, Element, EntityExt, Enum, Field, Func, GeneratedType, GeneratorEnv, NameDebug,
21 StrExt, settings,
22};
23
24mod desc;
25
26#[derive(Clone)]
27pub enum Class<'tu, 'ge> {
28 Clang {
29 entity: Entity<'tu>,
30 custom_fullname: Option<Rc<str>>,
31 gen_env: &'ge GeneratorEnv<'tu>,
32 },
33 Desc(Rc<ClassDesc<'tu, 'ge>>),
34}
35
36impl<'tu, 'ge> Class<'tu, 'ge> {
37 pub fn new(entity: Entity<'tu>, gen_env: &'ge GeneratorEnv<'tu>) -> Self {
38 Self::Clang {
39 entity,
40 custom_fullname: None,
41 gen_env,
42 }
43 }
44
45 pub fn new_ext(entity: Entity<'tu>, custom_fullname: impl Into<Rc<str>>, gen_env: &'ge GeneratorEnv<'tu>) -> Self {
46 Self::Clang {
47 entity,
48 custom_fullname: Some(custom_fullname.into()),
49 gen_env,
50 }
51 }
52
53 pub fn new_desc(desc: ClassDesc<'tu, 'ge>) -> Self {
54 Self::Desc(Rc::new(desc))
55 }
56
57 pub fn can_be_simple(&self) -> bool {
59 let cpp_refname = self.cpp_name(CppNameStyle::Reference);
60 settings::IMPLEMENTED_GENERICS.contains(cpp_refname.as_ref())
61 || self.has_fields()
62 && !self.has_descendants()
63 && !self.has_bases()
64 && !self
65 .for_each_field(|field| {
66 let type_ref = field.type_ref();
67 ControlFlow::continue_until(!type_ref.kind().is_copy(type_ref.type_hint()))
68 })
69 .is_break()
70 }
71
72 pub fn kind(&self) -> ClassKind {
73 match self {
74 &Self::Clang { entity, gen_env, .. } => {
75 if settings::ELEMENT_EXCLUDE_KIND
76 .get(self.cpp_name(CppNameStyle::Reference).as_ref())
77 .is_some_and(|ek| ek.is_excluded())
78 {
79 return ClassKind::Other;
80 }
81 match gen_env.get_export_config(entity).map(|c| c.class_kind_override) {
82 Some(ClassKindOverride::Simple) => {
83 if self.can_be_simple() {
84 ClassKind::Simple
85 } else {
86 ClassKind::BoxedForced
87 }
88 }
89 Some(ClassKindOverride::Boxed) => ClassKind::Boxed,
90 Some(ClassKindOverride::BoxedForced) => ClassKind::BoxedForced,
91 Some(ClassKindOverride::System) => ClassKind::System,
92 None => {
93 if self.is_system() {
94 ClassKind::System
95 } else if let Some(kind) = gen_env.get_class_kind(entity) {
96 match kind {
97 ClassKind::Simple if !self.can_be_simple() => ClassKind::BoxedForced,
98 _ => kind,
99 }
100 } else {
101 ClassKind::Other
102 }
103 }
104 }
105 }
106 Self::Desc(desc) => desc.kind,
107 }
108 }
109
110 pub fn type_ref(&self) -> TypeRef<'tu, 'ge> {
111 match self {
112 &Self::Clang { entity, gen_env, .. } => TypeRef::new(entity.get_type().expect("Can't get class type"), gen_env),
113 Self::Desc(desc) => TypeRef::guess(desc.cpp_fullname.as_ref(), desc.rust_module),
114 }
115 }
116
117 pub fn string_type(&self) -> Option<StrType> {
119 let cpp_refname = self.cpp_name(CppNameStyle::Reference);
120 if cpp_refname.starts_with("std::") && cpp_refname.ends_with("::string") {
121 Some(StrType::StdString(StrEnc::Text))
122 } else if cpp_refname == "cv::String" {
123 Some(StrType::CvString(StrEnc::Text))
124 } else {
125 None
126 }
127 }
128
129 pub fn template_kind(&self) -> TemplateKind<'tu, 'ge> {
130 match self {
131 &Self::Clang { entity, gen_env, .. } => {
132 if entity.get_template_kind().is_some() {
133 TemplateKind::Template
134 } else if let Some(template_entity) = entity.get_template() {
135 TemplateKind::Specialization(Self::new(template_entity, gen_env))
136 } else {
137 TemplateKind::No
138 }
139 }
140 Self::Desc(desc) => desc.template_kind.clone(),
141 }
142 }
143
144 pub fn is_abstract(&self) -> bool {
145 match self {
146 &Self::Clang { entity, .. } => entity.is_abstract_record(),
147 Self::Desc(desc) => desc.is_abstract,
148 }
149 }
150
151 pub fn is_polymorphic(&self) -> bool {
153 match self {
154 Self::Clang { entity, .. } => entity
155 .walk_methods_while(|f| ControlFlow::continue_until(f.is_virtual_method() || f.is_pure_virtual_method()))
156 .is_break(),
157 Self::Desc(_) => false,
158 }
159 }
160
161 pub fn as_enum(&self) -> Option<Enum<'tu, 'ge>> {
163 match self {
164 &Self::Clang { entity, gen_env, .. } => {
165 if !self.has_methods() && !self.has_fields() && !self.has_descendants() && !self.has_bases() {
166 let mut actual_children = entity
167 .get_children()
168 .into_iter()
169 .filter(|child| !matches!(child.get_kind(), EntityKind::AccessSpecifier | EntityKind::VisibilityAttr)); let first_child = actual_children.next();
171 let second_child = actual_children.next();
172 if let Some(single) = first_child
173 && second_child.is_none()
174 && matches!(single.get_kind(), EntityKind::EnumDecl)
175 {
176 Some(Enum::new_ext(
177 single,
178 self.cpp_name(CppNameStyle::Declaration).as_ref(),
179 gen_env,
180 ))
181 } else {
182 None
183 }
184 } else {
185 None
186 }
187 }
188 Self::Desc(_) => None,
189 }
190 }
191
192 pub fn has_explicit_clone(&self) -> bool {
194 self.for_each_method(|m| ControlFlow::continue_until(m.is_clone())).is_break()
195 }
196
197 pub fn has_implicit_clone(&self) -> bool {
199 !self.is_abstract() && matches!(self.kind(), ClassKind::BoxedForced) && !self.has_virtual_destructor()
200 }
201
202 pub fn has_implicit_default_constructor(&self) -> bool {
203 match self {
204 &Self::Clang { entity, .. } => !entity
205 .walk_children_while(|f| {
206 if matches!(f.get_kind(), EntityKind::Constructor) {
207 ControlFlow::Break(())
208 } else {
209 ControlFlow::Continue(())
210 }
211 })
212 .is_break(),
213 Self::Desc(_) => false,
214 }
215 }
216
217 pub fn has_virtual_destructor(&self) -> bool {
218 match self {
219 Class::Clang { entity, .. } => entity
220 .walk_children_while(|f| ControlFlow::continue_until(f.get_kind() == EntityKind::Destructor && f.is_virtual_method()))
221 .is_break(),
222 Class::Desc(_) => false,
223 }
224 }
225
226 pub fn has_private_destructor(&self) -> bool {
227 match self {
228 Class::Clang { entity, .. } => entity
229 .walk_children_while(|f| {
230 ControlFlow::continue_until(
231 f.get_kind() == EntityKind::Destructor && f.get_accessibility() != Some(Accessibility::Public),
232 )
233 })
234 .is_break(),
235 Class::Desc(_) => false,
236 }
237 }
238
239 pub fn has_bases(&self) -> bool {
240 match self {
241 &Self::Clang { entity, .. } => entity.walk_bases_while(|_| ControlFlow::Break(())).is_break(),
242 Self::Desc(desc) => !desc.bases.is_empty(),
243 }
244 }
245
246 pub fn bases(&self) -> Cow<'_, [Class<'tu, 'ge>]> {
247 match self {
248 &Self::Clang { entity, gen_env, .. } => {
249 let mut out = vec![];
250 let entity = entity.get_template().unwrap_or(entity);
251 let _ = entity.walk_bases_while(|child| {
252 out.push(Self::new(Self::definition_entity(child), gen_env));
253 ControlFlow::Continue(())
254 });
255 out.into()
256 }
257 Self::Desc(desc) => desc.bases.as_ref().into(),
258 }
259 }
260
261 pub fn all_bases(&self) -> HashSet<Class<'tu, 'ge>> {
262 #![expect(clippy::mutable_key_type)]
263 self
264 .bases()
265 .into_owned()
266 .into_iter()
267 .flat_map(|b| {
268 let mut out = b.all_bases();
269 out.insert(b);
270 out
271 })
272 .collect()
273 }
274
275 pub fn has_descendants(&self) -> bool {
276 match self {
277 &Self::Clang { gen_env, .. } => gen_env.descendants_of(&self.cpp_name(CppNameStyle::Reference)).is_some(),
278 Self::Desc(_) => false,
279 }
280 }
281
282 pub fn descendants(&self) -> HashSet<Class<'tu, 'ge>> {
283 #![expect(clippy::mutable_key_type)]
284 match self {
285 &Self::Clang { gen_env, .. } => gen_env
286 .descendants_of(&self.cpp_name(CppNameStyle::Reference))
287 .into_iter()
288 .flat_map(|desc| desc.iter().map(|e| Self::new(*e, gen_env)))
289 .collect(),
290 Self::Desc(_) => HashSet::new(),
291 }
292 }
293
294 pub fn all_descendants(&self) -> HashSet<Class<'tu, 'ge>> {
295 #![expect(clippy::mutable_key_type)]
296 self
297 .descendants()
298 .into_iter()
299 .flat_map(|descendant| {
300 let mut out = descendant.all_descendants();
301 out.insert(descendant);
302 out
303 })
304 .collect()
305 }
306
307 pub fn all_family(&self) -> HashSet<Class<'tu, 'ge>> {
308 #![expect(clippy::mutable_key_type)]
309 fn collect<'tu, 'ge>(out: &mut HashSet<Class<'tu, 'ge>>, cls: Class<'tu, 'ge>) {
310 if out.insert(cls.clone()) {
311 for base in cls.bases().into_owned() {
312 collect(out, base);
313 }
314 for desc in cls.descendants() {
315 collect(out, desc);
316 }
317 }
318 }
319
320 let mut out = HashSet::new();
321 collect(&mut out, self.clone());
322 out
323 }
324
325 pub fn has_methods(&self) -> bool {
326 self.for_each_method(|_| ControlFlow::Break(())).is_break()
327 }
328
329 #[inline]
330 pub fn for_each_method(&self, mut predicate: impl FnMut(Func<'tu, 'ge>) -> ControlFlow<()>) -> ControlFlow<()> {
331 match self {
332 &Self::Clang { entity, gen_env, .. } => entity.walk_methods_while(|f| predicate(Func::new(f, gen_env))),
333 Self::Desc(_) => ControlFlow::Continue(()),
334 }
335 }
336
337 pub fn methods(&self, filter: impl Fn(&Func) -> bool) -> Vec<Func<'tu, 'ge>> {
338 match self {
339 Class::Clang { entity, gen_env, .. } => {
340 let mut out = Vec::with_capacity(32);
341 let _ = entity.walk_methods_while(|func_entity| {
342 let func = Func::new(func_entity, gen_env);
343 let func: Func = if let Some(func_fact) = gen_env.settings.func_replace.get(&mut func.matcher()) {
344 func_fact(&func)
345 } else {
346 func
347 };
348 if func.is_generic()
349 && let Some(specs) = gen_env.settings.func_specialize.get(&mut func.matcher())
350 {
351 for spec in specs {
352 let spec_func = func.clone().specialize(spec);
353 if filter(&spec_func) {
354 out.push(spec_func);
355 }
356 }
357 return ControlFlow::Continue(());
358 }
359 if filter(&func) {
360 out.push(func);
361 }
362 ControlFlow::Continue(())
363 });
364 for inject_func_fact in &gen_env.settings.func_inject {
365 let inject_func: Func = inject_func_fact();
366 if let Some(cls) = inject_func.kind().as_class_method()
367 && cls == self
368 && filter(&inject_func)
369 {
370 out.push(inject_func);
371 }
372 }
373 out
374 }
375 Class::Desc(_) => vec![],
376 }
377 }
378
379 pub fn has_fields(&self) -> bool {
380 self.for_each_field(|_| ControlFlow::Break(())).is_break()
381 }
382
383 #[inline]
384 pub fn for_each_field(&self, mut predicate: impl FnMut(Field<'tu, 'ge>) -> ControlFlow<()>) -> ControlFlow<()> {
385 match self {
386 &Self::Clang { entity, gen_env, .. } => entity.walk_fields_while(|f| predicate(Field::new(f, gen_env))),
387 Self::Desc(_) => ControlFlow::Continue(()),
388 }
389 }
390
391 pub fn fields(&self, filter: impl Fn(&Field) -> bool) -> Vec<Field<'tu, 'ge>> {
392 let mut out = Vec::with_capacity(32);
393 let _ = self.for_each_field(|f| {
394 if filter(&f) {
395 out.push(f);
396 }
397 ControlFlow::Continue(())
398 });
399 out
400 }
401
402 #[inline]
403 pub fn for_each_const(&self, mut predicate: impl FnMut(Const<'tu>) -> ControlFlow<()>) -> ControlFlow<()> {
404 match self {
405 &Self::Clang { entity, .. } => entity.walk_consts_while(|f| predicate(Const::new(f))),
406 Self::Desc(_) => ControlFlow::Continue(()),
407 }
408 }
409
410 pub fn consts(&self) -> Vec<Const<'tu>> {
411 let mut out = Vec::with_capacity(8);
412 let _ = self.for_each_const(|c| {
413 out.push(c);
414 ControlFlow::Continue(())
415 });
416 out
417 }
418
419 pub fn field_methods<'f>(
420 &self,
421 fields: &'f [Field<'tu, 'ge>],
422 constness_filter: Option<Constness>,
423 ) -> impl Iterator<Item = Func<'tu, 'ge>> + 'f {
424 match self {
425 &Self::Clang { gen_env, .. } => {
426 let cls = self.clone();
427 let accessor_generator = move |fld: &Field<'tu, 'ge>| {
428 let doc_comment = Rc::from(fld.doc_comment());
429 let def_loc = fld.file_line_name().location;
430 let rust_module = fld.rust_module();
431 let mut fld_type_ref = fld.type_ref();
432 let fld_refname = fld.cpp_name(CppNameStyle::Reference);
433 if let Some(type_hint) = gen_env.settings.property_override.get(fld_refname.as_ref()) {
434 fld_type_ref.to_mut().set_type_hint(type_hint.clone());
435 } else {
436 let fld_type_kind = fld_type_ref.kind();
437 if fld_type_kind
438 .as_pointer()
439 .is_some_and(|inner| inner.kind().as_primitive().is_some())
440 && !fld_type_kind.is_char_ptr_string(fld_type_ref.type_hint())
441 {
442 fld_type_ref.to_mut().set_type_hint(TypeRefTypeHint::PrimitivePtrAsRaw);
443 } else if fld_type_kind.as_class().is_some_and(|cls| cls.kind().is_trait()) {
444 fld_type_ref.to_mut().set_type_hint(TypeRefTypeHint::TraitClassConcrete);
445 }
446 }
447 let fld_type_kind = fld_type_ref.kind();
448 let return_kind = ReturnKind::infallible(fld_type_kind.return_as_naked(fld_type_ref.type_hint()));
449 let fld_const = fld.constness();
450 let passed_by_ref = fld_type_kind.can_return_as_direct_reference();
451 let prop_tweak = gen_env.settings.property_tweaks.get(fld_refname.as_ref());
452 let rust_custom_leafname = prop_tweak.and_then(|tweak| tweak.rename);
453 let read_write = prop_tweak
454 .and_then(|tweak| tweak.read_write)
455 .unwrap_or(PropertyReadWrite::ReadWrite);
456 let fld_declname = fld_refname.localname();
457 let (mut read_const_yield, mut read_mut_yield) = if read_write.is_read() {
458 if fld_const.is_mut() && passed_by_ref {
459 let read_const_func = if constness_filter.is_none_or(|c| c.is_const()) {
460 Some(Func::new_desc(
461 FuncDesc::new(
462 FuncKind::FieldAccessor(cls.clone(), fld.clone()),
463 Constness::Const,
464 return_kind,
465 fld_declname,
466 rust_module,
467 [],
468 fld_type_ref.as_ref().clone().with_inherent_constness(Constness::Const),
469 )
470 .def_loc(def_loc.clone())
471 .doc_comment(Rc::clone(&doc_comment))
472 .cpp_body(FuncCppBody::ManualCall("{{name}}".into()))
473 .maybe_rust_custom_leafname(rust_custom_leafname),
474 ))
475 } else {
476 None
477 };
478 let read_mut_func = if constness_filter.is_none_or(|c| c.is_mut()) {
479 Some(Func::new_desc(
480 FuncDesc::new(
481 FuncKind::FieldAccessor(cls.clone(), fld.clone()),
482 Constness::Mut,
483 return_kind,
484 format!("{fld_declname}Mut"),
485 rust_module,
486 [],
487 fld_type_ref.as_ref().clone().with_inherent_constness(Constness::Mut),
488 )
489 .def_loc(def_loc.clone())
490 .doc_comment(Rc::clone(&doc_comment))
491 .cpp_body(FuncCppBody::ManualCall("{{name}}".into()))
492 .maybe_rust_custom_leafname(rust_custom_leafname.map(|name| format!("{name}_mut"))),
493 ))
494 } else {
495 None
496 };
497 (read_const_func, read_mut_func)
498 } else {
499 let single_read_func = if constness_filter.is_none_or(|c| c == fld_const) {
500 Some(Func::new_desc(
501 FuncDesc::new(
502 FuncKind::FieldAccessor(cls.clone(), fld.clone()),
503 fld_const,
504 return_kind,
505 fld_declname,
506 rust_module,
507 [],
508 fld_type_ref.as_ref().clone(),
509 )
510 .def_loc(def_loc.clone())
511 .doc_comment(Rc::clone(&doc_comment))
512 .cpp_body(FuncCppBody::ManualCall("{{name}}".into()))
513 .maybe_rust_custom_leafname(rust_custom_leafname),
514 ))
515 } else {
516 None
517 };
518 (single_read_func, None)
519 }
520 } else {
521 (None, None)
522 };
523 let mut write_yield = if read_write.is_write()
524 && constness_filter.is_none_or(|c| c.is_mut())
525 && !fld_type_ref.constness().is_const()
526 && !fld_type_kind.as_fixed_array().is_some()
527 {
528 let (first_letter, rest) = fld_declname.capitalize_first_ascii_letter().expect("Empty fld_declname");
529 Some(Func::new_desc(
530 FuncDesc::new(
531 FuncKind::FieldAccessor(cls.clone(), fld.clone()),
532 Constness::Mut,
533 ReturnKind::InfallibleNaked,
534 format!("set{first_letter}{rest}"),
535 rust_module,
536 [Field::new_desc(FieldDesc {
537 cpp_fullname: "val".into(),
538 type_ref: fld_type_ref.as_ref().clone().with_inherent_constness(Constness::Const),
539 default_value: fld.default_value().map(|v| v.into()),
540 })],
541 TypeRefDesc::void(),
542 )
543 .doc_comment(doc_comment)
544 .def_loc(def_loc)
545 .cpp_body(FuncCppBody::ManualCall("{{name}} = {{args}}".into()))
546 .maybe_rust_custom_leafname(rust_custom_leafname.map(|name| format!("set_{name}"))),
547 ))
548 } else {
549 None
550 };
551 iter::from_fn(move || {
552 read_const_yield
553 .take()
554 .or_else(|| read_mut_yield.take())
555 .or_else(|| write_yield.take())
556 .map(|f| {
557 if let Some(func_fact) = gen_env.settings.func_replace.get(&mut f.matcher()) {
558 func_fact(&f)
559 } else {
560 f
561 }
562 })
563 })
564 };
565 FieldMethodsIter::Clang(fields.iter().flat_map(accessor_generator))
566 }
567 Self::Desc(_) => FieldMethodsIter::Desc,
568 }
569 }
570
571 fn definition_entity(entity: Entity<'tu>) -> Entity<'tu> {
574 entity.get_template().unwrap_or(entity).get_definition().unwrap_or(entity)
575 }
576
577 pub fn is_definition(&self) -> bool {
578 match self {
579 &Self::Clang { entity, .. } => {
580 let class_loc = entity.get_location();
581 let def_loc = entity.get_definition().and_then(|d| d.get_location());
582 match (class_loc, def_loc) {
583 (Some(class_loc), Some(def_loc)) => class_loc == def_loc,
584 (_, None) => false,
585 _ => true,
586 }
587 }
588 Self::Desc(_) => true,
589 }
590 }
591
592 pub fn generated_types(&self) -> Vec<GeneratedType<'tu, 'ge>> {
593 self
594 .fields(|f| f.exclude_kind().is_included())
595 .into_iter()
596 .flat_map(|f| f.type_ref().generated_types())
597 .chain(
598 self
599 .methods(|m| m.exclude_kind().is_included())
600 .into_iter()
601 .flat_map(|m| m.generated_types()),
602 )
603 .collect()
604 }
605}
606
607impl<'tu> ToEntity<'tu> for &Class<'tu, '_> {
608 fn to_entity(self) -> Option<Entity<'tu>> {
609 match self {
610 Class::Clang { entity, .. } => Some(*entity),
611 Class::Desc(_) => None,
612 }
613 }
614}
615
616impl Element for Class<'_, '_> {
617 fn exclude_kind(&self) -> ExcludeKind {
618 match self {
619 Self::Clang { .. } => DefaultElement::exclude_kind(self)
620 .with_is_ignored(|| match self.kind() {
621 ClassKind::Other => true,
622 ClassKind::System => {
623 !settings::IMPLEMENTED_SYSTEM_CLASSES.contains(self.cpp_name(CppNameStyle::Reference).as_ref())
624 }
625 ClassKind::Simple | ClassKind::Boxed | ClassKind::BoxedForced => match self.template_kind() {
626 TemplateKind::Template => true,
627 TemplateKind::No => !self.is_definition() || self.cpp_namespace() == "",
628 TemplateKind::Specialization(_) => {
629 !settings::IMPLEMENTED_GENERICS.contains(self.cpp_name(CppNameStyle::Reference).as_ref())
630 }
631 },
632 })
633 .with_is_excluded(|| match self.kind() {
634 ClassKind::System | ClassKind::Other => true,
635 ClassKind::Simple => false,
636 ClassKind::Boxed | ClassKind::BoxedForced => self.has_private_destructor(),
637 }),
638 Self::Desc(desc) => desc.exclude_kind,
639 }
640 }
641
642 fn is_system(&self) -> bool {
643 match self {
644 &Self::Clang { entity, .. } => DefaultElement::is_system(entity),
645 Self::Desc(desc) => matches!(desc.kind, ClassKind::System),
646 }
647 }
648
649 fn is_public(&self) -> bool {
650 match self {
651 &Self::Clang { entity, .. } => DefaultElement::is_public(entity),
652 Self::Desc(desc) => desc.is_public,
653 }
654 }
655
656 fn doc_comment(&self) -> Cow<'_, str> {
657 match self {
658 Self::Clang { entity, .. } => entity.doc_comment(),
659 Self::Desc(_) => "".into(),
660 }
661 }
662
663 fn cpp_namespace(&self) -> Cow<'_, str> {
664 #[inline(always)]
665 fn inner(cpp_fullname: &str) -> Cow<'_, str> {
666 cpp_fullname.namespace().into()
667 }
668
669 match self {
670 Self::Clang {
671 custom_fullname: Some(cpp_fullname),
672 ..
673 } => inner(cpp_fullname.as_ref()),
674 Self::Clang { entity, .. } => DefaultElement::cpp_namespace(*entity).into(),
675 Self::Desc(desc) => inner(desc.cpp_fullname.as_ref()),
676 }
677 }
678
679 fn cpp_name(&self, style: CppNameStyle) -> Cow<'_, str> {
680 match self {
681 Self::Clang {
682 custom_fullname: Some(cpp_fullname),
683 ..
684 } => cpp_fullname.cpp_name_from_fullname(style).into(),
685 &Self::Clang { entity, .. } => DefaultElement::cpp_name(self, entity, style),
686 Self::Desc(desc) => desc.cpp_fullname.cpp_name_from_fullname(style).into(),
687 }
688 }
689}
690
691impl Hash for Class<'_, '_> {
692 fn hash<H: Hasher>(&self, state: &mut H) {
693 match self {
694 Self::Clang { entity, .. } => entity.hash(state),
695 Self::Desc(desc) => desc.hash(state),
696 }
697 }
698}
699
700impl PartialEq for Class<'_, '_> {
701 fn eq(&self, other: &Self) -> bool {
702 self.cpp_name(CppNameStyle::Reference) == other.cpp_name(CppNameStyle::Reference) && self.kind() == other.kind()
703 }
704}
705
706impl Eq for Class<'_, '_> {}
707
708impl<'me> NameDebug<'me> for &'me Class<'me, '_> {
709 fn file_line_name(self) -> LocationName<'me> {
710 match self {
711 Class::Clang { entity, .. } => entity.file_line_name(),
712 Class::Desc(desc) => LocationName::new(DefinitionLocation::Generated, desc.cpp_fullname.as_ref()),
713 }
714 }
715}
716
717impl fmt::Debug for Class<'_, '_> {
718 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
719 let mut props = vec![];
720 if self.can_be_simple() {
721 props.push("can_be_simple");
722 }
723 if self.template_kind().is_template() {
724 props.push("template");
725 }
726 if self.template_kind().as_template_specialization().is_some() {
727 props.push("template_specialization");
728 }
729 if self.is_abstract() {
730 props.push("abstract");
731 }
732 if self.is_polymorphic() {
733 props.push("polymorphic");
734 }
735 if self.kind().is_trait() {
736 props.push("trait");
737 }
738 if self.as_enum().is_some() {
739 props.push("enum");
740 }
741 if self.has_explicit_clone() {
742 props.push("has_explicit_clone");
743 }
744 if self.has_implicit_clone() {
745 props.push("has_implicit_clone");
746 }
747 if self.has_virtual_destructor() {
748 props.push("has_virtual_dtor");
749 }
750 if self.has_private_destructor() {
751 props.push("has_private_dtor")
752 }
753 if self.has_bases() {
754 props.push("has_bases");
755 }
756 if self.has_descendants() {
757 props.push("has_descendants");
758 }
759 if self.has_methods() {
760 props.push("has_methods");
761 }
762 if self.has_fields() {
763 props.push("has_fields");
764 }
765 if !self.consts().is_empty() {
766 props.push("has_consts");
767 }
768 if self.is_definition() {
769 props.push("definition");
770 }
771 if matches!(
772 self,
773 Self::Clang {
774 custom_fullname: Some(_),
775 ..
776 }
777 ) {
778 props.push("custom_fullname");
779 }
780 let mut debug_struct = f.debug_struct(match self {
781 Self::Clang { .. } => "Class::Clang",
782 Self::Desc(_) => "Class::Desc",
783 });
784 self
785 .update_debug_struct(&mut debug_struct)
786 .field("kind", &self.kind())
787 .field("props", &props.join(", "))
788 .field("string_type", &self.string_type())
789 .finish()
790 }
791}
792
793#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
794pub enum ClassKind {
795 Simple,
797 Boxed,
799 BoxedForced,
801 System,
803 Other,
805}
806
807impl ClassKind {
808 pub fn is_simple(self) -> bool {
809 match self {
810 Self::Simple => true,
811 Self::Boxed | Self::BoxedForced | Self::System | Self::Other => false,
812 }
813 }
814
815 pub fn is_boxed(self) -> bool {
816 match self {
817 Self::Boxed | Self::BoxedForced => true,
818 Self::Simple | Self::Other | Self::System => false,
819 }
820 }
821
822 pub fn is_trait(&self) -> bool {
823 match self {
824 Self::Boxed | Self::BoxedForced | Self::System => true,
825 Self::Simple | Self::Other => false,
826 }
827 }
828}
829
830#[derive(Clone, Debug, PartialEq, Eq, Hash)]
831pub enum TemplateKind<'tu, 'ge> {
832 No,
834 Template,
836 Specialization(Class<'tu, 'ge>),
838}
839
840impl<'tu, 'ge> TemplateKind<'tu, 'ge> {
841 pub fn is_template(&self) -> bool {
842 match self {
843 TemplateKind::Template => true,
844 TemplateKind::No | TemplateKind::Specialization(_) => false,
845 }
846 }
847
848 pub fn as_template_specialization(&self) -> Option<&Class<'tu, 'ge>> {
849 match self {
850 TemplateKind::Specialization(cls) => Some(cls),
851 TemplateKind::No | TemplateKind::Template => None,
852 }
853 }
854}
855
856pub enum FieldMethodsIter<'tu: 'ge, 'ge, I: Iterator<Item = Func<'tu, 'ge>>> {
857 Clang(I),
858 Desc,
859}
860
861impl<'tu, 'ge, I: Iterator<Item = Func<'tu, 'ge>>> Iterator for FieldMethodsIter<'tu, 'ge, I> {
862 type Item = Func<'tu, 'ge>;
863
864 fn next(&mut self) -> Option<Self::Item> {
865 match self {
866 FieldMethodsIter::Clang(iter) => iter.next(),
867 FieldMethodsIter::Desc => None,
868 }
869 }
870}