1 //! Intermediate representation for C/C++ enumerations. 2 3 use super::super::codegen::EnumVariation; 4 use super::context::{BindgenContext, TypeId}; 5 use super::item::Item; 6 use super::ty::TypeKind; 7 use clang; 8 use ir::annotations::Annotations; 9 use ir::item::ItemCanonicalPath; 10 use parse::{ClangItemParser, ParseError}; 11 use regex_set::RegexSet; 12 13 /// An enum representing custom handling that can be given to a variant. 14 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 15 pub enum EnumVariantCustomBehavior { 16 /// This variant will be a module containing constants. 17 ModuleConstify, 18 /// This variant will be constified, that is, forced to generate a constant. 19 Constify, 20 /// This variant will be hidden entirely from the resulting enum. 21 Hide, 22 } 23 24 /// A C/C++ enumeration. 25 #[derive(Debug)] 26 pub struct Enum { 27 /// The representation used for this enum; it should be an `IntKind` type or 28 /// an alias to one. 29 /// 30 /// It's `None` if the enum is a forward declaration and isn't defined 31 /// anywhere else, see `tests/headers/func_ptr_in_struct.h`. 32 repr: Option<TypeId>, 33 34 /// The different variants, with explicit values. 35 variants: Vec<EnumVariant>, 36 } 37 38 impl Enum { 39 /// Construct a new `Enum` with the given representation and variants. new(repr: Option<TypeId>, variants: Vec<EnumVariant>) -> Self40 pub fn new(repr: Option<TypeId>, variants: Vec<EnumVariant>) -> Self { 41 Enum { repr, variants } 42 } 43 44 /// Get this enumeration's representation. repr(&self) -> Option<TypeId>45 pub fn repr(&self) -> Option<TypeId> { 46 self.repr 47 } 48 49 /// Get this enumeration's variants. variants(&self) -> &[EnumVariant]50 pub fn variants(&self) -> &[EnumVariant] { 51 &self.variants 52 } 53 54 /// Construct an enumeration from the given Clang type. from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Result<Self, ParseError>55 pub fn from_ty( 56 ty: &clang::Type, 57 ctx: &mut BindgenContext, 58 ) -> Result<Self, ParseError> { 59 use clang_sys::*; 60 debug!("Enum::from_ty {:?}", ty); 61 62 if ty.kind() != CXType_Enum { 63 return Err(ParseError::Continue); 64 } 65 66 let declaration = ty.declaration().canonical(); 67 let repr = declaration 68 .enum_type() 69 .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); 70 let mut variants = vec![]; 71 72 // Assume signedness since the default type by the C standard is an int. 73 let is_signed = repr 74 .and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)) 75 .map_or(true, |ty| match *ty.kind() { 76 TypeKind::Int(ref int_kind) => int_kind.is_signed(), 77 ref other => { 78 panic!("Since when enums can be non-integers? {:?}", other) 79 } 80 }); 81 82 let type_name = ty.spelling(); 83 let type_name = if type_name.is_empty() { 84 None 85 } else { 86 Some(type_name) 87 }; 88 let type_name = type_name.as_ref().map(String::as_str); 89 90 let definition = declaration.definition().unwrap_or(declaration); 91 definition.visit(|cursor| { 92 if cursor.kind() == CXCursor_EnumConstantDecl { 93 let value = if is_signed { 94 cursor.enum_val_signed().map(EnumVariantValue::Signed) 95 } else { 96 cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) 97 }; 98 if let Some(val) = value { 99 let name = cursor.spelling(); 100 let annotations = Annotations::new(&cursor); 101 let custom_behavior = ctx 102 .parse_callbacks() 103 .and_then(|callbacks| { 104 callbacks 105 .enum_variant_behavior(type_name, &name, val) 106 }) 107 .or_else(|| { 108 let annotations = annotations.as_ref()?; 109 if annotations.hide() { 110 Some(EnumVariantCustomBehavior::Hide) 111 } else if annotations.constify_enum_variant() { 112 Some(EnumVariantCustomBehavior::Constify) 113 } else { 114 None 115 } 116 }); 117 118 let name = ctx 119 .parse_callbacks() 120 .and_then(|callbacks| { 121 callbacks.enum_variant_name(type_name, &name, val) 122 }) 123 .or_else(|| { 124 annotations 125 .as_ref()? 126 .use_instead_of()? 127 .last() 128 .cloned() 129 }) 130 .unwrap_or(name); 131 132 let comment = cursor.raw_comment(); 133 variants.push(EnumVariant::new( 134 name, 135 comment, 136 val, 137 custom_behavior, 138 )); 139 } 140 } 141 CXChildVisit_Continue 142 }); 143 Ok(Enum::new(repr, variants)) 144 } 145 is_matching_enum( &self, ctx: &BindgenContext, enums: &RegexSet, item: &Item, ) -> bool146 fn is_matching_enum( 147 &self, 148 ctx: &BindgenContext, 149 enums: &RegexSet, 150 item: &Item, 151 ) -> bool { 152 let path = item.canonical_path(ctx); 153 let enum_ty = item.expect_type(); 154 155 if enums.matches(&path[1..].join("::")) { 156 return true; 157 } 158 159 // Test the variants if the enum is anonymous. 160 if enum_ty.name().is_some() { 161 return false; 162 } 163 164 self.variants().iter().any(|v| enums.matches(&v.name())) 165 } 166 167 /// Returns the final representation of the enum. computed_enum_variation( &self, ctx: &BindgenContext, item: &Item, ) -> EnumVariation168 pub fn computed_enum_variation( 169 &self, 170 ctx: &BindgenContext, 171 item: &Item, 172 ) -> EnumVariation { 173 // ModuleConsts has higher precedence before Rust in order to avoid 174 // problems with overlapping match patterns. 175 if self.is_matching_enum( 176 ctx, 177 &ctx.options().constified_enum_modules, 178 item, 179 ) { 180 EnumVariation::ModuleConsts 181 } else if self.is_matching_enum( 182 ctx, 183 &ctx.options().bitfield_enums, 184 item, 185 ) { 186 EnumVariation::NewType { is_bitfield: true } 187 } else if self.is_matching_enum(ctx, &ctx.options().newtype_enums, item) 188 { 189 EnumVariation::NewType { is_bitfield: false } 190 } else if self.is_matching_enum( 191 ctx, 192 &ctx.options().rustified_enums, 193 item, 194 ) { 195 EnumVariation::Rust { 196 non_exhaustive: false, 197 } 198 } else if self.is_matching_enum( 199 ctx, 200 &ctx.options().rustified_non_exhaustive_enums, 201 item, 202 ) { 203 EnumVariation::Rust { 204 non_exhaustive: true, 205 } 206 } else if self.is_matching_enum( 207 ctx, 208 &ctx.options().constified_enums, 209 item, 210 ) { 211 EnumVariation::Consts 212 } else { 213 ctx.options().default_enum_style 214 } 215 } 216 } 217 218 /// A single enum variant, to be contained only in an enum. 219 #[derive(Debug)] 220 pub struct EnumVariant { 221 /// The name of the variant. 222 name: String, 223 224 /// An optional doc comment. 225 comment: Option<String>, 226 227 /// The integer value of the variant. 228 val: EnumVariantValue, 229 230 /// The custom behavior this variant may have, if any. 231 custom_behavior: Option<EnumVariantCustomBehavior>, 232 } 233 234 /// A constant value assigned to an enumeration variant. 235 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 236 pub enum EnumVariantValue { 237 /// A signed constant. 238 Signed(i64), 239 240 /// An unsigned constant. 241 Unsigned(u64), 242 } 243 244 impl EnumVariant { 245 /// Construct a new enumeration variant from the given parts. new( name: String, comment: Option<String>, val: EnumVariantValue, custom_behavior: Option<EnumVariantCustomBehavior>, ) -> Self246 pub fn new( 247 name: String, 248 comment: Option<String>, 249 val: EnumVariantValue, 250 custom_behavior: Option<EnumVariantCustomBehavior>, 251 ) -> Self { 252 EnumVariant { 253 name, 254 comment, 255 val, 256 custom_behavior, 257 } 258 } 259 260 /// Get this variant's name. name(&self) -> &str261 pub fn name(&self) -> &str { 262 &self.name 263 } 264 265 /// Get this variant's value. val(&self) -> EnumVariantValue266 pub fn val(&self) -> EnumVariantValue { 267 self.val 268 } 269 270 /// Get this variant's documentation. comment(&self) -> Option<&str>271 pub fn comment(&self) -> Option<&str> { 272 self.comment.as_ref().map(|s| &**s) 273 } 274 275 /// Returns whether this variant should be enforced to be a constant by code 276 /// generation. force_constification(&self) -> bool277 pub fn force_constification(&self) -> bool { 278 self.custom_behavior 279 .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) 280 } 281 282 /// Returns whether the current variant should be hidden completely from the 283 /// resulting rust enum. hidden(&self) -> bool284 pub fn hidden(&self) -> bool { 285 self.custom_behavior 286 .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) 287 } 288 } 289