@@ -8,25 +8,44 @@ use clang::{Entity, EntityKind, EntityVisitResult};
88use crate :: debug:: LocationName ;
99use crate :: element:: ExcludeKind ;
1010use 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
0 commit comments