1use super::super::codegen::EnumVariation;
4use super::context::{BindgenContext, TypeId};
5use super::function::Visibility;
6use super::item::Item;
7use super::ty::{Type, TypeKind};
8use crate::clang;
9use crate::ir::annotations::Annotations;
10use crate::parse::ParseError;
11use crate::regex_set::RegexSet;
12
13#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub enum EnumVariantCustomBehavior {
16 ModuleConstify,
18 Constify,
20 Hide,
22}
23
24#[derive(Debug)]
26pub(crate) struct Enum {
27 repr: Option<TypeId>,
33
34 variants: Vec<EnumVariant>,
36
37 pub(crate) visibility: Visibility,
40}
41
42impl Enum {
43 pub(crate) fn new(
45 repr: Option<TypeId>,
46 variants: Vec<EnumVariant>,
47 visibility: Visibility,
48 ) -> Self {
49 Enum {
50 repr,
51 variants,
52 visibility,
53 }
54 }
55
56 pub(crate) fn repr(&self) -> Option<TypeId> {
58 self.repr
59 }
60
61 pub(crate) fn variants(&self) -> &[EnumVariant] {
63 &self.variants
64 }
65
66 pub(crate) fn from_ty(
68 ty: &clang::Type,
69 visibility: Visibility,
70 ctx: &mut BindgenContext,
71 ) -> Result<Self, ParseError> {
72 use clang_sys::*;
73 debug!("Enum::from_ty {ty:?}");
74
75 if ty.kind() != CXType_Enum {
76 return Err(ParseError::Continue);
77 }
78
79 let declaration = ty.declaration().canonical();
80 let repr = declaration
81 .enum_type()
82 .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok());
83 let mut variants = vec![];
84
85 let variant_ty =
86 repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx));
87 let is_bool = variant_ty.is_some_and(Type::is_bool);
88
89 let is_signed = variant_ty.map_or(true, |ty| match *ty.kind() {
91 TypeKind::Int(ref int_kind) => int_kind.is_signed(),
92 ref other => {
93 panic!("Since when enums can be non-integers? {other:?}")
94 }
95 });
96
97 let type_name = ty.spelling();
98 let type_name = if type_name.is_empty() {
99 None
100 } else {
101 Some(type_name)
102 };
103 let type_name = type_name.as_deref();
104
105 let definition = declaration.definition().unwrap_or(declaration);
106 definition.visit(|cursor| {
107 if cursor.kind() == CXCursor_EnumConstantDecl {
108 let value = if is_bool {
109 cursor.enum_val_boolean().map(EnumVariantValue::Boolean)
110 } else if is_signed {
111 cursor.enum_val_signed().map(EnumVariantValue::Signed)
112 } else {
113 cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned)
114 };
115 if let Some(val) = value {
116 let name = cursor.spelling();
117 let annotations = Annotations::new(&cursor);
118 let custom_behavior = ctx
119 .options()
120 .last_callback(|callbacks| {
121 callbacks
122 .enum_variant_behavior(type_name, &name, val)
123 })
124 .or_else(|| {
125 let annotations = annotations.as_ref()?;
126 if annotations.hide() {
127 Some(EnumVariantCustomBehavior::Hide)
128 } else if annotations.constify_enum_variant() {
129 Some(EnumVariantCustomBehavior::Constify)
130 } else {
131 None
132 }
133 });
134
135 let new_name = ctx
136 .options()
137 .last_callback(|callbacks| {
138 callbacks.enum_variant_name(type_name, &name, val)
139 })
140 .or_else(|| {
141 annotations
142 .as_ref()?
143 .use_instead_of()?
144 .last()
145 .cloned()
146 })
147 .unwrap_or_else(|| name.clone());
148
149 let comment = cursor.raw_comment();
150 variants.push(EnumVariant::new(
151 new_name,
152 name,
153 comment,
154 val,
155 custom_behavior,
156 ));
157 }
158 }
159 CXChildVisit_Continue
160 });
161 Ok(Enum::new(repr, variants, visibility))
162 }
163
164 fn is_matching_enum(
165 &self,
166 ctx: &BindgenContext,
167 enums: &RegexSet,
168 item: &Item,
169 ) -> bool {
170 let path = item.path_for_allowlisting(ctx);
171 let enum_ty = item.expect_type();
172
173 if enums.matches(path[1..].join("::")) {
174 return true;
175 }
176
177 if enum_ty.name().is_some() {
179 return false;
180 }
181
182 self.variants().iter().any(|v| enums.matches(v.name()))
183 }
184
185 pub(crate) fn computed_enum_variation(
187 &self,
188 ctx: &BindgenContext,
189 item: &Item,
190 ) -> EnumVariation {
191 if self.is_matching_enum(
194 ctx,
195 &ctx.options().constified_enum_modules,
196 item,
197 ) {
198 EnumVariation::ModuleConsts
199 } else if self.is_matching_enum(
200 ctx,
201 &ctx.options().bitfield_enums,
202 item,
203 ) {
204 EnumVariation::NewType {
205 is_bitfield: true,
206 is_global: false,
207 }
208 } else if self.is_matching_enum(ctx, &ctx.options().newtype_enums, item)
209 {
210 EnumVariation::NewType {
211 is_bitfield: false,
212 is_global: false,
213 }
214 } else if self.is_matching_enum(
215 ctx,
216 &ctx.options().newtype_global_enums,
217 item,
218 ) {
219 EnumVariation::NewType {
220 is_bitfield: false,
221 is_global: true,
222 }
223 } else if self.is_matching_enum(
224 ctx,
225 &ctx.options().rustified_enums,
226 item,
227 ) {
228 EnumVariation::Rust {
229 non_exhaustive: false,
230 }
231 } else if self.is_matching_enum(
232 ctx,
233 &ctx.options().rustified_non_exhaustive_enums,
234 item,
235 ) {
236 EnumVariation::Rust {
237 non_exhaustive: true,
238 }
239 } else if self.is_matching_enum(
240 ctx,
241 &ctx.options().constified_enums,
242 item,
243 ) {
244 EnumVariation::Consts
245 } else {
246 ctx.options().default_enum_style
247 }
248 }
249}
250
251#[derive(Debug)]
253pub(crate) struct EnumVariant {
254 name: String,
256
257 name_for_allowlisting: String,
259
260 comment: Option<String>,
262
263 val: EnumVariantValue,
265
266 custom_behavior: Option<EnumVariantCustomBehavior>,
268}
269
270#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
272pub enum EnumVariantValue {
273 Boolean(bool),
275
276 Signed(i64),
278
279 Unsigned(u64),
281}
282
283impl EnumVariant {
284 pub(crate) fn new(
286 name: String,
287 name_for_allowlisting: String,
288 comment: Option<String>,
289 val: EnumVariantValue,
290 custom_behavior: Option<EnumVariantCustomBehavior>,
291 ) -> Self {
292 EnumVariant {
293 name,
294 name_for_allowlisting,
295 comment,
296 val,
297 custom_behavior,
298 }
299 }
300
301 pub(crate) fn name(&self) -> &str {
303 &self.name
304 }
305
306 pub(crate) fn name_for_allowlisting(&self) -> &str {
308 &self.name_for_allowlisting
309 }
310
311 pub(crate) fn val(&self) -> EnumVariantValue {
313 self.val
314 }
315
316 pub(crate) fn comment(&self) -> Option<&str> {
318 self.comment.as_deref()
319 }
320
321 pub(crate) fn force_constification(&self) -> bool {
324 self.custom_behavior == Some(EnumVariantCustomBehavior::Constify)
325 }
326
327 pub(crate) fn hidden(&self) -> bool {
330 self.custom_behavior == Some(EnumVariantCustomBehavior::Hide)
331 }
332}