@@ -6,7 +6,7 @@ use aster;
6
6
use ir:: annotations:: FieldAccessorKind ;
7
7
use ir:: comp:: { CompInfo , CompKind , Field , Method } ;
8
8
use ir:: context:: BindgenContext ;
9
- use ir:: enum_ty:: Enum ;
9
+ use ir:: enum_ty:: { Enum , EnumVariant , EnumVariantValue } ;
10
10
use ir:: function:: { Function , FunctionSig } ;
11
11
use ir:: int:: IntKind ;
12
12
use ir:: item:: { Item , ItemCanonicalName , ItemCanonicalPath , ItemId } ;
@@ -1224,17 +1224,127 @@ impl MethodCodegen for Method {
1224
1224
}
1225
1225
}
1226
1226
1227
+ /// A helper type to construct enums, either bitfield ones or rust-style ones.
1228
+ enum EnumBuilder < ' a > {
1229
+ Rust ( aster:: item:: ItemEnumBuilder < aster:: invoke:: Identity > ) ,
1230
+ Bitfield {
1231
+ canonical_name : & ' a str ,
1232
+ aster : P < ast:: Item > ,
1233
+ } ,
1234
+ }
1235
+
1236
+ impl < ' a > EnumBuilder < ' a > {
1237
+ /// Create a new enum given an item builder, a canonical name, a name for
1238
+ /// the representation, and whether it should be represented as a rust enum.
1239
+ fn new ( aster : aster:: item:: ItemBuilder < aster:: invoke:: Identity > ,
1240
+ name : & ' a str ,
1241
+ repr_name : & str ,
1242
+ is_rust : bool )
1243
+ -> Self {
1244
+ if is_rust {
1245
+ EnumBuilder :: Rust ( aster. enum_ ( name) )
1246
+ } else {
1247
+ EnumBuilder :: Bitfield {
1248
+ canonical_name : name,
1249
+ aster : aster. tuple_struct ( name)
1250
+ . field ( )
1251
+ . pub_ ( )
1252
+ . ty ( )
1253
+ . id ( repr_name)
1254
+ . build ( ) ,
1255
+ }
1256
+ }
1257
+ }
1258
+
1259
+ /// Add a variant to this enum.
1260
+ fn with_variant ( self ,
1261
+ ctx : & BindgenContext ,
1262
+ variant : & EnumVariant ,
1263
+ mangling_prefix : Option < & String > ,
1264
+ rust_ty : P < ast:: Ty > ,
1265
+ result : & mut CodegenResult )
1266
+ -> Self {
1267
+ let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1268
+ let expr = aster:: AstBuilder :: new ( ) . expr ( ) ;
1269
+ let expr = match variant. val ( ) {
1270
+ EnumVariantValue :: Signed ( v) => expr. int ( v) ,
1271
+ EnumVariantValue :: Unsigned ( v) => expr. uint ( v) ,
1272
+ } ;
1273
+
1274
+ match self {
1275
+ EnumBuilder :: Rust ( b) => {
1276
+ EnumBuilder :: Rust ( b. with_variant_ ( ast:: Variant_ {
1277
+ name : ctx. rust_ident ( & * variant_name) ,
1278
+ attrs : vec ! [ ] ,
1279
+ data : ast:: VariantData :: Unit ( ast:: DUMMY_NODE_ID ) ,
1280
+ disr_expr : Some ( expr) ,
1281
+ } ) )
1282
+ }
1283
+ EnumBuilder :: Bitfield { canonical_name, .. } => {
1284
+ let constant_name = match mangling_prefix {
1285
+ Some ( prefix) => {
1286
+ Cow :: Owned ( format ! ( "{}_{}" , prefix, variant_name) )
1287
+ }
1288
+ None => variant_name,
1289
+ } ;
1290
+
1291
+ let constant = aster:: AstBuilder :: new ( )
1292
+ . item ( )
1293
+ . pub_ ( )
1294
+ . const_ ( & * constant_name)
1295
+ . expr ( )
1296
+ . call ( )
1297
+ . id ( canonical_name)
1298
+ . arg ( )
1299
+ . build ( expr)
1300
+ . build ( )
1301
+ . build ( rust_ty) ;
1302
+ result. push ( constant) ;
1303
+ self
1304
+ }
1305
+ }
1306
+ }
1307
+
1308
+ fn build ( self ,
1309
+ ctx : & BindgenContext ,
1310
+ rust_ty : P < ast:: Ty > ,
1311
+ result : & mut CodegenResult )
1312
+ -> P < ast:: Item > {
1313
+ match self {
1314
+ EnumBuilder :: Rust ( b) => b. build ( ) ,
1315
+ EnumBuilder :: Bitfield { canonical_name, aster } => {
1316
+ let rust_ty_name = ctx. rust_ident_raw ( canonical_name) ;
1317
+ let prefix = ctx. trait_prefix ( ) ;
1318
+
1319
+ let impl_ = quote_item ! ( ctx. ext_cx( ) ,
1320
+ impl :: $prefix:: ops:: BitOr <$rust_ty> for $rust_ty {
1321
+ type Output = Self ;
1322
+
1323
+ #[ inline]
1324
+ fn bitor( self , other: Self ) -> Self {
1325
+ $rust_ty_name( self . 0 | other. 0 )
1326
+ }
1327
+ }
1328
+ )
1329
+ . unwrap ( ) ;
1330
+
1331
+ result. push ( impl_) ;
1332
+ aster
1333
+ }
1334
+ }
1335
+ }
1336
+ }
1337
+
1227
1338
impl CodeGenerator for Enum {
1228
1339
type Extra = Item ;
1229
1340
1230
1341
fn codegen ( & self ,
1231
1342
ctx : & BindgenContext ,
1232
1343
result : & mut CodegenResult ,
1233
1344
item : & Item ) {
1234
- use ir:: enum_ty:: EnumVariantValue ;
1235
-
1236
1345
let name = item. canonical_name ( ctx) ;
1237
- let layout = item. expect_type ( ) . layout ( ctx) ;
1346
+ let enum_ty = item. expect_type ( ) ;
1347
+ let layout = enum_ty. layout ( ctx) ;
1238
1348
1239
1349
let repr = self . repr ( ) . map ( |repr| ctx. resolve_type ( repr) ) ;
1240
1350
let repr = match repr {
@@ -1270,10 +1380,24 @@ impl CodeGenerator for Enum {
1270
1380
1271
1381
let mut builder = aster:: AstBuilder :: new ( ) . item ( ) . pub_ ( ) ;
1272
1382
1383
+ let is_bitfield = {
1384
+ ctx. options ( ) . bitfield_enums . matches ( & name) ||
1385
+ ( enum_ty. name ( ) . is_none ( ) &&
1386
+ self . variants ( )
1387
+ . iter ( )
1388
+ . any ( |v| ctx. options ( ) . bitfield_enums . matches ( & v. name ( ) ) ) )
1389
+ } ;
1390
+
1391
+ let is_rust_enum = !is_bitfield;
1392
+
1273
1393
// FIXME: Rust forbids repr with empty enums. Remove this condition when
1274
1394
// this is allowed.
1275
- if !self . variants ( ) . is_empty ( ) {
1276
- builder = builder. with_attr ( attributes:: repr ( repr_name) ) ;
1395
+ if is_rust_enum {
1396
+ if !self . variants ( ) . is_empty ( ) {
1397
+ builder = builder. with_attr ( attributes:: repr ( repr_name) ) ;
1398
+ }
1399
+ } else {
1400
+ builder = builder. with_attr ( attributes:: repr ( "C" ) ) ;
1277
1401
}
1278
1402
1279
1403
if let Some ( comment) = item. comment ( ) {
@@ -1289,8 +1413,6 @@ impl CodeGenerator for Enum {
1289
1413
1290
1414
builder = builder. with_attr ( derives) ;
1291
1415
1292
- let mut builder = builder. enum_ ( & name) ;
1293
-
1294
1416
fn add_constant ( enum_ : & Type ,
1295
1417
// Only to avoid recomputing every time.
1296
1418
enum_canonical_name : & str ,
@@ -1318,52 +1440,64 @@ impl CodeGenerator for Enum {
1318
1440
result. push ( constant) ;
1319
1441
}
1320
1442
1321
- // Used to mangle the constants we generate in the unnamed-enum case.
1322
- let mut parent_canonical_name = None ;
1443
+ let mut builder =
1444
+ EnumBuilder :: new ( builder , & name , repr_name , is_rust_enum ) ;
1323
1445
1324
1446
// A map where we keep a value -> variant relation.
1325
1447
let mut seen_values = HashMap :: < _ , String > :: new ( ) ;
1326
- let enum_ty = item. expect_type ( ) ;
1327
1448
let enum_rust_ty = item. to_rust_ty ( ctx) ;
1449
+ let is_toplevel = item. is_toplevel ( ctx) ;
1450
+
1451
+ // Used to mangle the constants we generate in the unnamed-enum case.
1452
+ let parent_canonical_name = if is_toplevel {
1453
+ None
1454
+ } else {
1455
+ Some ( item. parent_id ( ) . canonical_name ( ctx) )
1456
+ } ;
1457
+
1458
+ let constant_mangling_prefix = if enum_ty. name ( ) . is_none ( ) {
1459
+ parent_canonical_name. as_ref ( ) . map ( |n| & * n)
1460
+ } else {
1461
+ Some ( & name)
1462
+ } ;
1463
+
1328
1464
for variant in self . variants ( ) . iter ( ) {
1329
1465
match seen_values. entry ( variant. val ( ) ) {
1330
1466
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) ;
1467
+ if is_rust_enum {
1468
+ let existing_variant_name = entry. get ( ) ;
1469
+ let variant_name = ctx. rust_mangle ( variant. name ( ) ) ;
1470
+ add_constant ( enum_ty,
1471
+ & name,
1472
+ & * variant_name,
1473
+ existing_variant_name,
1474
+ enum_rust_ty. clone ( ) ,
1475
+ result) ;
1476
+ } else {
1477
+ builder = builder. with_variant ( ctx,
1478
+ variant,
1479
+ constant_mangling_prefix,
1480
+ enum_rust_ty. clone ( ) ,
1481
+ result) ;
1482
+ }
1339
1483
}
1340
1484
Entry :: Vacant ( entry) => {
1341
- let expr = aster:: AstBuilder :: new ( ) . expr ( ) ;
1342
- let expr = match variant. val ( ) {
1343
- EnumVariantValue :: Signed ( val) => expr. int ( val) ,
1344
- EnumVariantValue :: Unsigned ( val) => expr. uint ( val) ,
1345
- } ;
1485
+ builder = builder. with_variant ( ctx,
1486
+ variant,
1487
+ constant_mangling_prefix,
1488
+ enum_rust_ty. clone ( ) ,
1489
+ result) ;
1490
+
1346
1491
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
- } ) ;
1353
1492
1354
1493
// If it's an unnamed enum, we also generate a constant so
1355
1494
// it can be properly accessed.
1356
- if enum_ty. name ( ) . is_none ( ) {
1495
+ if is_rust_enum && enum_ty. name ( ) . is_none ( ) {
1357
1496
// NB: if we want to do this for other kind of nested
1358
1497
// enums we can probably mangle the name.
1359
- let mangled_name = if item . is_toplevel ( ctx ) {
1498
+ let mangled_name = if is_toplevel {
1360
1499
variant_name. clone ( )
1361
1500
} else {
1362
- if parent_canonical_name. is_none ( ) {
1363
- parent_canonical_name = Some ( item. parent_id ( )
1364
- . canonical_name ( ctx) ) ;
1365
- }
1366
-
1367
1501
let parent_name = parent_canonical_name. as_ref ( )
1368
1502
. unwrap ( ) ;
1369
1503
@@ -1384,8 +1518,8 @@ impl CodeGenerator for Enum {
1384
1518
}
1385
1519
}
1386
1520
1387
-
1388
- result. push ( builder . build ( ) ) ;
1521
+ let enum_ = builder . build ( ctx , enum_rust_ty , result ) ;
1522
+ result. push ( enum_ ) ;
1389
1523
}
1390
1524
}
1391
1525
0 commit comments