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