@@ -1224,6 +1224,79 @@ impl MethodCodegen for Method {
1224
1224
}
1225
1225
}
1226
1226
1227
+ enum EnumBuilder < ' a > {
1228
+ Rust ( aster:: item:: ItemEnumBuilder < aster:: invoke:: Identity > ) ,
1229
+ Bitfield {
1230
+ canonical_name : & ' a str ,
1231
+ aster : P < ast:: Item > ,
1232
+ } ,
1233
+ }
1234
+
1235
+ impl < ' a > EnumBuilder < ' a > {
1236
+ fn new ( aster : aster:: item:: ItemBuilder < aster:: invoke:: Identity > ,
1237
+ name : & ' a str ,
1238
+ repr_name : & str ,
1239
+ is_rust : bool )
1240
+ -> Self {
1241
+ if is_rust {
1242
+ EnumBuilder :: Rust ( aster. enum_ ( name) )
1243
+ } else {
1244
+ EnumBuilder :: Bitfield {
1245
+ canonical_name : name,
1246
+ aster : aster. tuple_struct ( name)
1247
+ . field ( )
1248
+ . pub_ ( )
1249
+ . ty ( )
1250
+ . id ( repr_name)
1251
+ . build ( ) ,
1252
+ }
1253
+ }
1254
+ }
1255
+
1256
+ fn with_variant_ ( self ,
1257
+ ctx : & BindgenContext ,
1258
+ name : & str ,
1259
+ expr : P < ast:: Expr > ,
1260
+ rust_ty : P < ast:: Ty > ,
1261
+ result : & mut CodegenResult )
1262
+ -> Self {
1263
+ match self {
1264
+ EnumBuilder :: Rust ( b) => {
1265
+ EnumBuilder :: Rust ( b. with_variant_ ( ast:: Variant_ {
1266
+ name : ctx. rust_ident ( name) ,
1267
+ attrs : vec ! [ ] ,
1268
+ data : ast:: VariantData :: Unit ( ast:: DUMMY_NODE_ID ) ,
1269
+ disr_expr : Some ( expr) ,
1270
+ } ) )
1271
+ }
1272
+ EnumBuilder :: Bitfield { canonical_name, .. } => {
1273
+ // FIXME: Probably if unnamed we should be smarter! Easy to
1274
+ // improve.
1275
+ let constant_name = format ! ( "{}_{}" , canonical_name, name) ;
1276
+ let constant = aster:: AstBuilder :: new ( )
1277
+ . item ( )
1278
+ . const_ ( constant_name)
1279
+ . expr ( )
1280
+ . call ( )
1281
+ . id ( canonical_name)
1282
+ . arg ( )
1283
+ . build ( expr)
1284
+ . build ( )
1285
+ . build ( rust_ty) ;
1286
+ result. push ( constant) ;
1287
+ self
1288
+ }
1289
+ }
1290
+ }
1291
+
1292
+ fn build ( self ) -> P < ast:: Item > {
1293
+ match self {
1294
+ EnumBuilder :: Rust ( b) => b. build ( ) ,
1295
+ EnumBuilder :: Bitfield { aster, .. } => aster,
1296
+ }
1297
+ }
1298
+ }
1299
+
1227
1300
impl CodeGenerator for Enum {
1228
1301
type Extra = Item ;
1229
1302
@@ -1234,7 +1307,8 @@ impl CodeGenerator for Enum {
1234
1307
use ir:: enum_ty:: EnumVariantValue ;
1235
1308
1236
1309
let name = item. canonical_name ( ctx) ;
1237
- let layout = item. expect_type ( ) . layout ( ctx) ;
1310
+ let enum_ty = item. expect_type ( ) ;
1311
+ let layout = enum_ty. layout ( ctx) ;
1238
1312
1239
1313
let repr = self . repr ( ) . map ( |repr| ctx. resolve_type ( repr) ) ;
1240
1314
let repr = match repr {
@@ -1270,10 +1344,24 @@ impl CodeGenerator for Enum {
1270
1344
1271
1345
let mut builder = aster:: AstBuilder :: new ( ) . item ( ) . pub_ ( ) ;
1272
1346
1347
+ let is_bitfield = {
1348
+ ctx. options ( ) . bitfield_enums . matches ( & name) ||
1349
+ ( enum_ty. name ( ) . is_none ( ) &&
1350
+ self . variants ( )
1351
+ . iter ( )
1352
+ . any ( |v| ctx. options ( ) . bitfield_enums . matches ( & v. name ( ) ) ) )
1353
+ } ;
1354
+
1355
+ let is_rust_enum = !is_bitfield;
1356
+
1273
1357
// FIXME: Rust forbids repr with empty enums. Remove this condition when
1274
1358
// this is allowed.
1275
- if !self . variants ( ) . is_empty ( ) {
1276
- builder = builder. with_attr ( attributes:: repr ( repr_name) ) ;
1359
+ if is_rust_enum {
1360
+ if !self . variants ( ) . is_empty ( ) {
1361
+ builder = builder. with_attr ( attributes:: repr ( repr_name) ) ;
1362
+ }
1363
+ } else {
1364
+ builder = builder. with_attr ( attributes:: repr ( "C" ) ) ;
1277
1365
}
1278
1366
1279
1367
if let Some ( comment) = item. comment ( ) {
@@ -1289,8 +1377,6 @@ impl CodeGenerator for Enum {
1289
1377
1290
1378
builder = builder. with_attr ( derives) ;
1291
1379
1292
- let mut builder = builder. enum_ ( & name) ;
1293
-
1294
1380
fn add_constant ( enum_ : & Type ,
1295
1381
// Only to avoid recomputing every time.
1296
1382
enum_canonical_name : & str ,
@@ -1321,21 +1407,38 @@ impl CodeGenerator for Enum {
1321
1407
// Used to mangle the constants we generate in the unnamed-enum case.
1322
1408
let mut parent_canonical_name = None ;
1323
1409
1410
+ let mut builder =
1411
+ EnumBuilder :: new ( builder, & name, repr_name, is_rust_enum) ;
1412
+
1324
1413
// A map where we keep a value -> variant relation.
1325
1414
let mut seen_values = HashMap :: < _ , String > :: new ( ) ;
1326
- let enum_ty = item. expect_type ( ) ;
1327
1415
let enum_rust_ty = item. to_rust_ty ( ctx) ;
1328
1416
for variant in self . variants ( ) . iter ( ) {
1329
1417
match seen_values. entry ( variant. val ( ) ) {
1330
1418
Entry :: Occupied ( ref entry) => {
1331
- let existing_variant_name = entry. get ( ) ;
1332
- let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1333
- add_constant ( enum_ty,
1334
- & name,
1335
- & * variant_name,
1336
- existing_variant_name,
1337
- enum_rust_ty. clone ( ) ,
1338
- result) ;
1419
+ if is_rust_enum {
1420
+ let existing_variant_name = entry. get ( ) ;
1421
+ let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1422
+ add_constant ( enum_ty,
1423
+ & name,
1424
+ & * variant_name,
1425
+ existing_variant_name,
1426
+ enum_rust_ty. clone ( ) ,
1427
+ result) ;
1428
+ } else {
1429
+ // FIXME: Don't repeat this block below.
1430
+ let expr = aster:: AstBuilder :: new ( ) . expr ( ) ;
1431
+ let expr = match variant. val ( ) {
1432
+ EnumVariantValue :: Signed ( val) => expr. int ( val) ,
1433
+ EnumVariantValue :: Unsigned ( val) => expr. uint ( val) ,
1434
+ } ;
1435
+ let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1436
+ builder = builder. with_variant_ ( ctx,
1437
+ & * variant_name,
1438
+ expr,
1439
+ enum_rust_ty. clone ( ) ,
1440
+ result) ;
1441
+ }
1339
1442
}
1340
1443
Entry :: Vacant ( entry) => {
1341
1444
let expr = aster:: AstBuilder :: new ( ) . expr ( ) ;
@@ -1344,16 +1447,15 @@ impl CodeGenerator for Enum {
1344
1447
EnumVariantValue :: Unsigned ( val) => expr. uint ( val) ,
1345
1448
} ;
1346
1449
let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1347
- builder = builder. with_variant_ ( ast:: Variant_ {
1348
- name : ctx. rust_ident ( & * variant_name) ,
1349
- attrs : vec ! [ ] ,
1350
- data : ast:: VariantData :: Unit ( ast:: DUMMY_NODE_ID ) ,
1351
- disr_expr : Some ( expr) ,
1352
- } ) ;
1450
+ builder = builder. with_variant_ ( ctx,
1451
+ & * variant_name,
1452
+ expr,
1453
+ enum_rust_ty. clone ( ) ,
1454
+ result) ;
1353
1455
1354
1456
// If it's an unnamed enum, we also generate a constant so
1355
1457
// it can be properly accessed.
1356
- if enum_ty. name ( ) . is_none ( ) {
1458
+ if is_rust_enum && enum_ty. name ( ) . is_none ( ) {
1357
1459
// NB: if we want to do this for other kind of nested
1358
1460
// enums we can probably mangle the name.
1359
1461
let mangled_name = if item. is_toplevel ( ctx) {
@@ -1384,7 +1486,6 @@ impl CodeGenerator for Enum {
1384
1486
}
1385
1487
}
1386
1488
1387
-
1388
1489
result. push ( builder. build ( ) ) ;
1389
1490
}
1390
1491
}
0 commit comments