opencv_binding_generator/
enumeration.rs

1use std::borrow::Cow;
2use std::fmt;
3use std::ops::ControlFlow;
4use std::rc::Rc;
5
6use clang::{Entity, EntityKind, EntityVisitResult};
7
8use crate::comment::strip_doxygen_comment_markers;
9use crate::debug::LocationName;
10use crate::element::ExcludeKind;
11use crate::type_ref::CppNameStyle;
12use crate::{Const, DefaultElement, Element, EntityElement, EntityExt, NameDebug, StrExt};
13
14#[derive(Clone, PartialEq)]
15pub struct Enum<'tu> {
16	entity: Entity<'tu>,
17	custom_fullname: Option<Rc<str>>,
18}
19
20impl<'tu> Enum<'tu> {
21	pub fn new(entity: Entity<'tu>) -> Self {
22		Self {
23			entity,
24			custom_fullname: None,
25		}
26	}
27
28	pub fn new_ext(entity: Entity<'tu>, custom_fullname: impl Into<Rc<str>>) -> Self {
29		Self {
30			entity,
31			custom_fullname: Some(custom_fullname.into()),
32		}
33	}
34
35	pub fn is_anonymous(&self) -> bool {
36		self.entity.is_anonymous() || /* clang-6 quirk */ self.cpp_name(CppNameStyle::Declaration).starts_with("(anonymous enum")
37	}
38
39	pub fn as_typedefed(&self) -> Option<Entity<'tu>> {
40		if matches!(self.entity.get_kind(), EntityKind::TypedefDecl | EntityKind::TypeAliasDecl) {
41			let mut child = None;
42			let _ = self.entity.walk_children_while(|c| {
43				child = Some(c);
44				ControlFlow::Break(())
45			});
46			Some(child.expect("Invalid anonymous typedefed enum"))
47		} else {
48			None
49		}
50	}
51
52	pub fn consts(&self) -> Vec<Const<'tu>> {
53		let mut out = vec![];
54		self.as_typedefed().unwrap_or(self.entity).visit_children(|const_decl, _| {
55			if const_decl.get_kind() == EntityKind::EnumConstantDecl {
56				out.push(Const::new(const_decl));
57			}
58			EntityVisitResult::Continue
59		});
60		out
61	}
62}
63
64impl<'tu> EntityElement<'tu> for Enum<'tu> {
65	fn entity(&self) -> Entity<'tu> {
66		self.entity
67	}
68}
69
70impl Element for Enum<'_> {
71	fn exclude_kind(&self) -> ExcludeKind {
72		DefaultElement::exclude_kind(self).with_is_excluded(|| self.as_typedefed().is_some())
73	}
74
75	fn is_system(&self) -> bool {
76		DefaultElement::is_system(self.entity)
77	}
78
79	fn is_public(&self) -> bool {
80		DefaultElement::is_public(self.entity)
81	}
82
83	fn doc_comment(&self) -> Cow<str> {
84		strip_doxygen_comment_markers(&self.entity.get_comment().unwrap_or_default()).into()
85	}
86
87	fn cpp_namespace(&self) -> Cow<str> {
88		if let Some(custom_fullname) = &self.custom_fullname {
89			custom_fullname.namespace().into()
90		} else {
91			DefaultElement::cpp_namespace(self.entity).into()
92		}
93	}
94
95	fn cpp_name(&self, style: CppNameStyle) -> Cow<str> {
96		if let Some(custom_fullname) = self.custom_fullname.as_deref() {
97			custom_fullname.cpp_name_from_fullname(style).into()
98		} else {
99			DefaultElement::cpp_name(self, self.entity(), style)
100		}
101	}
102}
103
104impl<'me> NameDebug<'me> for &'me Enum<'_> {
105	fn file_line_name(self) -> LocationName<'me> {
106		self.entity.file_line_name()
107	}
108}
109
110impl fmt::Debug for Enum<'_> {
111	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112		let mut debug_struct = f.debug_struct("Enum");
113		self
114			.update_debug_struct(&mut debug_struct)
115			.field("consts", &self.consts())
116			.finish()
117	}
118}