opencv_binding_generator/
typedef.rs

1use std::borrow::Cow;
2use std::fmt;
3use std::ops::ControlFlow;
4use std::rc::Rc;
5
6use clang::{Entity, EntityKind};
7pub use desc::TypedefDesc;
8
9use crate::debug::{DefinitionLocation, LocationName};
10use crate::element::ExcludeKind;
11use crate::type_ref::{CppNameStyle, NameStyle, TypeRefDesc, TypeRefKind, TypeRefTypeHint};
12use crate::writer::rust_native::type_ref::TypeRefExt;
13use crate::{
14	settings, Class, Constness, DefaultElement, Element, EntityExt, Enum, GeneratedType, GeneratorEnv, NameDebug, StrExt, TypeRef,
15};
16
17mod desc;
18
19#[derive(Clone)]
20pub enum Typedef<'tu, 'ge> {
21	Clang {
22		entity: Entity<'tu>,
23		gen_env: &'ge GeneratorEnv<'tu>,
24	},
25	Desc(Rc<TypedefDesc<'tu, 'ge>>),
26}
27
28impl<'tu, 'ge> Typedef<'tu, 'ge> {
29	/// Create a corresponding type from EntityKind::TypedefDecl or EntityKind::TypeAliasDecl.
30	///
31	/// Sometimes the actual type is not a `TypeDef`, but a `Class` for example in case of:
32	/// ```c
33	/// typedef struct
34	/// {
35	///   int x, y, w, h;
36	///   float score;
37	/// } Box;
38	/// ```
39	pub fn try_new(entity: Entity<'tu>, gen_env: &'ge GeneratorEnv<'tu>) -> NewTypedefResult<'tu, 'ge> {
40		let mut out = NewTypedefResult::Typedef(Self::Clang { entity, gen_env });
41		let _ = entity.walk_children_while(|child| {
42			let child_unnamed_or_same_name = child
43				.get_name()
44				.map_or(true, |child_name| Some(child_name) == entity.get_name());
45			if child_unnamed_or_same_name {
46				match child.get_kind() {
47					EntityKind::StructDecl => {
48						out = NewTypedefResult::Class(Class::new_ext(child, entity.cpp_name(CppNameStyle::Reference), gen_env));
49					}
50					EntityKind::EnumDecl => {
51						out = NewTypedefResult::Enum(Enum::new_ext(child, entity.cpp_name(CppNameStyle::Reference), gen_env));
52					}
53					_ => {}
54				}
55			}
56			ControlFlow::Break(())
57		});
58		out
59	}
60
61	pub fn new_desc(desc: TypedefDesc<'tu, 'ge>) -> Self {
62		Self::Desc(Rc::new(desc))
63	}
64
65	pub fn type_ref(&self) -> TypeRef<'tu, 'ge> {
66		match self {
67			Self::Clang { entity, gen_env } => TypeRef::new(entity.get_type().expect("Can't get typedef type"), gen_env),
68			Self::Desc(desc) => TypeRef::new_desc(TypeRefDesc::new(
69				TypeRefKind::Typedef(Self::Desc(Rc::clone(desc))),
70				Constness::Mut,
71			)),
72		}
73	}
74
75	pub fn underlying_type_ref(&self) -> TypeRef<'tu, 'ge> {
76		match self {
77			Self::Clang { entity, gen_env } => TypeRef::new_ext(
78				entity
79					.get_typedef_underlying_type()
80					.expect("Can't get typedef underlying type"),
81				TypeRefTypeHint::None,
82				Some(*entity),
83				gen_env,
84			),
85			Self::Desc(desc) => desc.underlying_type.clone(),
86		}
87	}
88
89	pub fn generated_types(&self) -> Vec<GeneratedType<'tu, 'ge>> {
90		self.underlying_type_ref().generated_types()
91	}
92}
93
94impl Element for Typedef<'_, '_> {
95	fn exclude_kind(&self) -> ExcludeKind {
96		DefaultElement::exclude_kind(self)
97			.with_exclude_kind(|| self.underlying_type_ref().exclude_kind())
98			.with_is_excluded(|| {
99				settings::PRIMITIVE_TYPEDEFS.contains_key(self.cpp_name(CppNameStyle::Reference).as_ref()) || {
100					let underlying_type = self.underlying_type_ref();
101					// fixes recursive typedefs like Cv16suf or GKernelPackage
102					// fixme: don't rely on rust name to disconnect this generic module from rust_native
103					self.type_ref().rust_name(NameStyle::ref_()) == underlying_type.rust_name(NameStyle::ref_())
104				}
105			})
106	}
107
108	fn is_system(&self) -> bool {
109		match self {
110			Self::Clang { entity, .. } => DefaultElement::is_system(*entity),
111			Self::Desc(_) => false,
112		}
113	}
114
115	fn is_public(&self) -> bool {
116		match self {
117			Self::Clang { entity, .. } => DefaultElement::is_public(*entity),
118			Self::Desc(_) => true,
119		}
120	}
121
122	fn doc_comment(&self) -> Cow<'_, str> {
123		match self {
124			Self::Clang { entity, .. } => entity.doc_comment(),
125			Self::Desc(_) => "".into(),
126		}
127	}
128
129	fn cpp_namespace(&self) -> Cow<'_, str> {
130		match self {
131			Self::Clang { entity, .. } => DefaultElement::cpp_namespace(*entity).into(),
132			Self::Desc(desc) => desc.cpp_fullname.namespace().into(),
133		}
134	}
135
136	fn cpp_name(&self, style: CppNameStyle) -> Cow<'_, str> {
137		match self {
138			Self::Clang { entity, .. } => DefaultElement::cpp_name(self, *entity, style),
139			Self::Desc(desc) => desc.cpp_fullname.cpp_name_from_fullname(style).into(),
140		}
141	}
142}
143
144pub enum NewTypedefResult<'tu, 'ge> {
145	Typedef(Typedef<'tu, 'ge>),
146	Class(Class<'tu, 'ge>),
147	Enum(Enum<'tu, 'ge>),
148}
149
150impl NewTypedefResult<'_, '_> {
151	pub fn exclude_kind(&self) -> ExcludeKind {
152		match self {
153			NewTypedefResult::Typedef(tdef) => tdef.exclude_kind(),
154			NewTypedefResult::Class(cls) => cls.exclude_kind(),
155			NewTypedefResult::Enum(enm) => enm.exclude_kind(),
156		}
157	}
158}
159
160impl<'me> NameDebug<'me> for &'me Typedef<'_, '_> {
161	fn file_line_name(self) -> LocationName<'me> {
162		match self {
163			Typedef::Clang { entity, .. } => entity.file_line_name(),
164			Typedef::Desc(desc) => LocationName::new(DefinitionLocation::Generated, desc.cpp_fullname.as_ref()),
165		}
166	}
167}
168
169impl PartialEq for Typedef<'_, '_> {
170	fn eq(&self, other: &Self) -> bool {
171		self.cpp_name(CppNameStyle::Reference) == other.cpp_name(CppNameStyle::Reference)
172	}
173}
174
175impl fmt::Debug for Typedef<'_, '_> {
176	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177		let mut debug_struct = f.debug_struct(match self {
178			Self::Clang { .. } => "Typedef::Clang",
179			Self::Desc(_) => "Typedef::Desc",
180		});
181		self
182			.update_debug_struct(&mut debug_struct)
183			.field("underlying_type_ref", &self.underlying_type_ref())
184			.finish()
185	}
186}