Skip to content

Commit 760f582

Browse files
committed
Implement bitfield enums
1 parent d09a4be commit 760f582

File tree

20 files changed

+561
-94
lines changed

20 files changed

+561
-94
lines changed

binding-generator/src/class.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,18 @@ impl<'tu, 'ge> Class<'tu, 'ge> {
159159
}
160160

161161
/// Special case of an empty class with only an anonymous enum inside (e.g., DrawLinesMatchesFlags)
162-
pub fn as_enum(&self) -> Option<Enum<'tu>> {
162+
pub fn as_enum(&self) -> Option<Enum<'tu, 'ge>> {
163163
match self {
164-
&Self::Clang { entity, .. } => {
164+
&Self::Clang { entity, gen_env, .. } => {
165165
if !self.has_methods() && !self.has_fields() && !self.has_descendants() && !self.has_bases() {
166166
let children = entity.get_children();
167167
if let [single] = children.as_slice() {
168168
if matches!(single.get_kind(), EntityKind::EnumDecl) {
169-
Some(Enum::new_ext(*single, self.cpp_name(CppNameStyle::Declaration).as_ref()))
169+
Some(Enum::new_ext(
170+
*single,
171+
self.cpp_name(CppNameStyle::Declaration).as_ref(),
172+
gen_env,
173+
))
170174
} else {
171175
None
172176
}

binding-generator/src/enumeration.rs

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,44 @@ use clang::{Entity, EntityKind, EntityVisitResult};
88
use crate::debug::LocationName;
99
use crate::element::ExcludeKind;
1010
use crate::type_ref::CppNameStyle;
11-
use crate::{Const, DefaultElement, Element, EntityElement, EntityExt, NameDebug, StrExt};
11+
use crate::{Const, DefaultElement, Element, EntityElement, EntityExt, GeneratorEnv, NameDebug, StrExt};
1212

13-
#[derive(Clone, PartialEq)]
14-
pub struct Enum<'tu> {
13+
#[derive(Debug, Clone, Copy)]
14+
pub enum EnumBitfield {
15+
NotBitfield,
16+
BitfieldWithoutZero,
17+
BitfieldWithZero,
18+
}
19+
20+
impl EnumBitfield {
21+
pub fn is_bitfield(self) -> bool {
22+
match self {
23+
Self::NotBitfield => false,
24+
Self::BitfieldWithoutZero | Self::BitfieldWithZero => true,
25+
}
26+
}
27+
}
28+
29+
#[derive(Clone)]
30+
pub struct Enum<'tu, 'ge> {
1531
entity: Entity<'tu>,
32+
gen_env: &'ge GeneratorEnv<'tu>,
1633
custom_fullname: Option<Rc<str>>,
1734
}
1835

19-
impl<'tu> Enum<'tu> {
20-
pub fn new(entity: Entity<'tu>) -> Self {
36+
impl<'tu, 'ge> Enum<'tu, 'ge> {
37+
pub fn new(entity: Entity<'tu>, gen_env: &'ge GeneratorEnv<'tu>) -> Self {
2138
Self {
2239
entity,
40+
gen_env,
2341
custom_fullname: None,
2442
}
2543
}
2644

27-
pub fn new_ext(entity: Entity<'tu>, custom_fullname: impl Into<Rc<str>>) -> Self {
45+
pub fn new_ext(entity: Entity<'tu>, custom_fullname: impl Into<Rc<str>>, gen_env: &'ge GeneratorEnv<'tu>) -> Self {
2846
Self {
2947
entity,
48+
gen_env,
3049
custom_fullname: Some(custom_fullname.into()),
3150
}
3251
}
@@ -58,15 +77,69 @@ impl<'tu> Enum<'tu> {
5877
});
5978
out
6079
}
80+
81+
/// True if this enum is bitfield, e.g. intended to be used as a combination of flags.
82+
pub fn bitfield(&self) -> EnumBitfield {
83+
let name = self.cpp_name(CppNameStyle::Reference);
84+
if name.ends_with("Flags") || name.ends_with("FLAGS") || name.ends_with("Settings") {
85+
self
86+
.gen_env
87+
.settings
88+
.enum_bitfield_override
89+
.get(name.as_ref())
90+
.copied()
91+
.unwrap_or_else(|| {
92+
let mut has_zero = false;
93+
let mut var_count = 0;
94+
let not_bitfield = self.as_typedefed().unwrap_or(self.entity).visit_children(|const_decl, _| {
95+
if const_decl.get_kind() != EntityKind::EnumConstantDecl {
96+
return EntityVisitResult::Continue;
97+
}
98+
if let Some(val) = const_decl
99+
.get_enum_constant_value()
100+
.and_then(|(val, _)| u64::try_from(val).ok())
101+
{
102+
var_count += 1;
103+
if val == 0 {
104+
has_zero = true;
105+
EntityVisitResult::Continue
106+
} else if val.is_power_of_two() {
107+
EntityVisitResult::Continue
108+
} else {
109+
EntityVisitResult::Break
110+
}
111+
} else {
112+
EntityVisitResult::Break
113+
}
114+
});
115+
if not_bitfield {
116+
EnumBitfield::NotBitfield
117+
} else if has_zero {
118+
if var_count <= 2 {
119+
// enum with 0 and one/no other option is self-exclusive, no point in bitfield machinery
120+
EnumBitfield::NotBitfield
121+
} else {
122+
EnumBitfield::BitfieldWithZero
123+
}
124+
} else if var_count <= 1 {
125+
EnumBitfield::NotBitfield
126+
} else {
127+
EnumBitfield::BitfieldWithoutZero
128+
}
129+
})
130+
} else {
131+
EnumBitfield::NotBitfield
132+
}
133+
}
61134
}
62135

63-
impl<'tu> EntityElement<'tu> for Enum<'tu> {
136+
impl<'tu> EntityElement<'tu> for Enum<'tu, '_> {
64137
fn entity(&self) -> Entity<'tu> {
65138
self.entity
66139
}
67140
}
68141

69-
impl Element for Enum<'_> {
142+
impl Element for Enum<'_, '_> {
70143
fn exclude_kind(&self) -> ExcludeKind {
71144
DefaultElement::exclude_kind(self).with_is_excluded(|| self.as_typedefed().is_some())
72145
}
@@ -100,13 +173,19 @@ impl Element for Enum<'_> {
100173
}
101174
}
102175

103-
impl<'me> NameDebug<'me> for &'me Enum<'_> {
176+
impl PartialEq for Enum<'_, '_> {
177+
fn eq(&self, other: &Self) -> bool {
178+
self.entity == other.entity && self.custom_fullname == other.custom_fullname
179+
}
180+
}
181+
182+
impl<'me> NameDebug<'me> for &'me Enum<'_, '_> {
104183
fn file_line_name(self) -> LocationName<'me> {
105184
self.entity.file_line_name()
106185
}
107186
}
108187

109-
impl fmt::Debug for Enum<'_> {
188+
impl fmt::Debug for Enum<'_, '_> {
110189
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111190
let mut debug_struct = f.debug_struct("Enum");
112191
self

binding-generator/src/generator.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub trait GeneratorVisitor<'tu>: Sized {
5656
fn visit_const(&mut self, cnst: Const<'tu>) {}
5757

5858
/// Top-level enum
59-
fn visit_enum(&mut self, enm: Enum<'tu>) {}
59+
fn visit_enum(&mut self, enm: Enum<'tu, '_>) {}
6060

6161
/// Top-level function
6262
fn visit_func(&mut self, func: Func<'tu, '_>) {}
@@ -142,7 +142,7 @@ impl<'tu, V: GeneratorVisitor<'tu>> EntityWalkerVisitor<'tu> for OpenCvWalker<'t
142142
| EntityKind::ClassTemplate
143143
| EntityKind::ClassTemplatePartialSpecialization
144144
| EntityKind::StructDecl => Self::process_class(&mut self.visitor, &mut self.gen_env, entity),
145-
EntityKind::EnumDecl => Self::process_enum(&mut self.visitor, entity),
145+
EntityKind::EnumDecl => Self::process_enum(&mut self.visitor, &self.gen_env, entity),
146146
EntityKind::FunctionDecl => Self::process_func(&mut self.visitor, &mut self.func_names, &self.gen_env, entity),
147147
EntityKind::TypedefDecl | EntityKind::TypeAliasDecl => Self::process_typedef(&mut self.visitor, &self.gen_env, entity),
148148
EntityKind::VarDecl => {
@@ -237,7 +237,7 @@ impl<'tu, 'r, V: GeneratorVisitor<'tu>> OpenCvWalker<'tu, 'r, V> {
237237
visitor.visit_generated_type(dep);
238238
});
239239
let _ = class_decl.walk_enums_while(|enm| {
240-
Self::process_enum(visitor, enm);
240+
Self::process_enum(visitor, gen_env, enm);
241241
ControlFlow::Continue(())
242242
});
243243
let _ = class_decl.walk_classes_while(|sub_cls| {
@@ -265,8 +265,8 @@ impl<'tu, 'r, V: GeneratorVisitor<'tu>> OpenCvWalker<'tu, 'r, V> {
265265
}
266266
}
267267

268-
fn process_enum(visitor: &mut V, enum_decl: Entity<'tu>) {
269-
let enm = Enum::new(enum_decl);
268+
fn process_enum(visitor: &mut V, gen_env: &GeneratorEnv<'tu>, enum_decl: Entity<'tu>) {
269+
let enm = Enum::new(enum_decl, gen_env);
270270
if enm.exclude_kind().is_included() {
271271
for cnst in enm.consts() {
272272
if cnst.exclude_kind().is_included() {

binding-generator/src/settings.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub use class_tweaks::{class_tweaks_factory, ClassTweak, ClassTweaks};
5151
pub use const_tweak::CONST_TYPE_OVERRIDE;
5252
pub use element_exclude_kind::ELEMENT_EXCLUDE_KIND;
5353
pub use element_export_tweak::ELEMENT_EXPORT_TWEAK;
54+
pub use enum_bitfield_override::{enum_bitfield_override_factory, EnumBitfieldOverride};
5455
pub use force_infallible::{force_infallible_factory, ForceInfallible};
5556
pub use func_cfg_attr::{func_cfg_attr_factory, FuncCfgAttr, CFG_ATTR_NOT_ON_WINDOWS, CFG_ATTR_ONLY_OPENCV_5};
5657
pub use func_companion_tweak::{func_companion_tweak_factory, CompanionTweak, FuncCompanionTweak};
@@ -77,6 +78,7 @@ mod class_tweaks;
7778
mod const_tweak;
7879
mod element_exclude_kind;
7980
mod element_export_tweak;
81+
mod enum_bitfield_override;
8082
mod force_infallible;
8183
mod func_cfg_attr;
8284
mod func_companion_tweak;
@@ -97,6 +99,7 @@ pub type TypeRefFactory = fn() -> TypeRef<'static, 'static>;
9799
pub struct Settings {
98100
pub arg_override: ArgOverride,
99101
pub return_override: ReturnOverride,
102+
pub enum_bitfield_override: EnumBitfieldOverride,
100103
pub force_infallible: ForceInfallible,
101104
pub func_cfg_attr: FuncCfgAttr,
102105
pub func_companion_tweak: FuncCompanionTweak,
@@ -117,6 +120,7 @@ impl Settings {
117120
Self {
118121
arg_override: ArgOverride::empty(),
119122
return_override: ReturnOverride::empty(),
123+
enum_bitfield_override: EnumBitfieldOverride::default(),
120124
force_infallible: ForceInfallible::empty(),
121125
func_cfg_attr: FuncCfgAttr::empty(),
122126
func_companion_tweak: FuncCompanionTweak::empty(),
@@ -137,6 +141,7 @@ impl Settings {
137141
Self {
138142
arg_override: arg_override_factory(module),
139143
return_override: return_override_factory(module),
144+
enum_bitfield_override: enum_bitfield_override_factory(module),
140145
force_infallible: force_infallible_factory(module),
141146
func_cfg_attr: func_cfg_attr_factory(module),
142147
func_companion_tweak: func_companion_tweak_factory(module),
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::collections::HashMap;
2+
3+
use EnumBitfield::NotBitfield;
4+
5+
use crate::enumeration::EnumBitfield;
6+
use crate::SupportedModule;
7+
8+
pub type EnumBitfieldOverride = HashMap<&'static str, EnumBitfield>;
9+
10+
/// cpp_name(Reference)
11+
pub fn enum_bitfield_override_factory(module: SupportedModule) -> EnumBitfieldOverride {
12+
match module {
13+
SupportedModule::Core => HashMap::from([("cv::RotateFlags", NotBitfield)]),
14+
SupportedModule::ImgCodecs => HashMap::from([("cv::ImwriteEXRTypeFlags", NotBitfield)]),
15+
_ => HashMap::new(),
16+
}
17+
}

binding-generator/src/type_ref/desc.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,10 @@ impl<'tu> ClangTypeExt<'tu> for Type<'tu> {
511511
}
512512
}
513513

514-
TypeKind::Enum => TypeRefKind::Enum(Enum::new(self.get_declaration().expect("Can't get enum declaration"))),
514+
TypeKind::Enum => TypeRefKind::Enum(Enum::new(
515+
self.get_declaration().expect("Can't get enum declaration"),
516+
gen_env,
517+
)),
515518

516519
TypeKind::FunctionPrototype => {
517520
if let Some(parent) = parent_entity {

binding-generator/src/type_ref/kind.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub enum TypeRefKind<'tu, 'ge> {
2323
RValueReference(TypeRef<'tu, 'ge>),
2424
SmartPtr(SmartPtr<'tu, 'ge>),
2525
Class(Class<'tu, 'ge>),
26-
Enum(Enum<'tu>),
26+
Enum(Enum<'tu, 'ge>),
2727
Function(Function<'tu, 'ge>),
2828
Typedef(Typedef<'tu, 'ge>),
2929
Generic(String),
@@ -161,7 +161,7 @@ impl<'tu, 'ge> TypeRefKind<'tu, 'ge> {
161161
}
162162
}
163163

164-
pub fn as_enum(&self) -> Option<&Enum<'tu>> {
164+
pub fn as_enum(&self) -> Option<&Enum<'tu, 'ge>> {
165165
if let TypeRefKind::Enum(out) = self {
166166
Some(out)
167167
} else {

binding-generator/src/typedef.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'tu, 'ge> Typedef<'tu, 'ge> {
4848
out = NewTypedefResult::Class(Class::new_ext(child, entity.cpp_name(CppNameStyle::Reference), gen_env));
4949
}
5050
EntityKind::EnumDecl => {
51-
out = NewTypedefResult::Enum(Enum::new_ext(child, entity.cpp_name(CppNameStyle::Reference)));
51+
out = NewTypedefResult::Enum(Enum::new_ext(child, entity.cpp_name(CppNameStyle::Reference), gen_env));
5252
}
5353
_ => {}
5454
}
@@ -144,7 +144,7 @@ impl Element for Typedef<'_, '_> {
144144
pub enum NewTypedefResult<'tu, 'ge> {
145145
Typedef(Typedef<'tu, 'ge>),
146146
Class(Class<'tu, 'ge>),
147-
Enum(Enum<'tu>),
147+
Enum(Enum<'tu, 'ge>),
148148
}
149149

150150
impl NewTypedefResult<'_, '_> {

0 commit comments

Comments
 (0)