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