Skip to content

Commit 3675788

Browse files
committed
add enum styles
1 parent ca48925 commit 3675788

File tree

8 files changed

+379
-4
lines changed

8 files changed

+379
-4
lines changed

engine/src/conversion/analysis/fun/mod.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,6 +2049,7 @@ impl<'a> FnAnalyzer<'a> {
20492049
/// Also fills out the [`PodAndConstructorAnalysis::constructors`] fields with information useful
20502050
/// for further analysis phases.
20512051
fn add_constructors_present(&mut self, mut apis: ApiVec<FnPrePhase1>) -> ApiVec<FnPrePhase2> {
2052+
let enums = self.config.get_enums();
20522053
let all_items_found = find_constructors_present(&apis);
20532054
for (self_ty, items_found) in all_items_found.iter() {
20542055
if self.config.exclude_impls {
@@ -2057,10 +2058,8 @@ impl<'a> FnAnalyzer<'a> {
20572058
// messy, see the comment on this function for why.
20582059
continue;
20592060
}
2060-
if self
2061-
.config
2062-
.is_on_constructor_blocklist(&self_ty.to_cpp_name())
2063-
{
2061+
let cpp_name = self_ty.to_cpp_name();
2062+
if self.config.is_on_constructor_blocklist(&cpp_name) || enums.contains(&cpp_name) {
20642063
continue;
20652064
}
20662065
let path = self_ty.to_type_path();

engine/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,22 @@ impl IncludeCppEngine {
381381
.allowlist_var(&a);
382382
}
383383
}
384+
385+
for (style, enums) in &self.config.enum_styles.0 {
386+
use autocxx_parser::EnumStyle::*;
387+
let apply: fn(bindgen::Builder, &String) -> bindgen::Builder = match style {
388+
BitfieldEnum => |b, e| b.bitfield_enum(e),
389+
NewtypeEnum => |b, e| b.newtype_enum(e),
390+
// NewtypeGlobalEnum => |b, e| b.newtype_global_enum(e),
391+
RustifiedEnum => |b, e| b.rustified_enum(e),
392+
RustifiedNonExhaustiveEnum => |b, e| b.rustified_non_exhaustive_enum(e),
393+
// ConstifiedEnumModule => |b, e| b.constified_enum_module(e),
394+
// ConstifiedEnum => |b, e| b.constified_enum(e),
395+
};
396+
for name in enums {
397+
builder = apply(builder, name);
398+
}
399+
}
384400

385401
for item in &self.config.opaquelist {
386402
builder = builder.opaque_type(item);

integration-tests/tests/integration_test.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,179 @@ fn test_enum_with_funcs() {
11151115
run_test(cxx, hdr, rs, &["Bob", "give_bob"], &[]);
11161116
}
11171117

1118+
#[test]
1119+
fn test_bitfield_enum() {
1120+
let hdr = indoc! {"
1121+
#include <cstdint>
1122+
enum SomeFlags : int {
1123+
FLAG_A = 1 << 0, // 0x1
1124+
FLAG_B = 1 << 2, // 0x4
1125+
FLAG_C = FLAG_A | FLAG_B, // 0x5
1126+
};
1127+
"};
1128+
let hexathorpe = Token![#](Span::call_site());
1129+
let rs = quote! {
1130+
use autocxx::prelude::*;
1131+
include_cpp! {
1132+
#hexathorpe include "input.h"
1133+
safety!(unsafe_ffi)
1134+
enum_style!(BitfieldEnum, "SomeFlags")
1135+
generate_pod!("SomeFlags")
1136+
}
1137+
1138+
fn main() {
1139+
let a = ffi::SomeFlags::FLAG_A;
1140+
let b = ffi::SomeFlags::FLAG_B;
1141+
let c = ffi::SomeFlags::FLAG_C;
1142+
assert_eq!(a.0, 0x1);
1143+
assert_eq!(b.0, 0x4);
1144+
assert_eq!(c.0, 0x5);
1145+
1146+
let aob = ffi::SomeFlags::FLAG_A | ffi::SomeFlags::FLAG_B;
1147+
assert_eq!(aob.0, 0x5);
1148+
assert_eq!(aob.0, ffi::SomeFlags::FLAG_C.0);
1149+
1150+
let anb = ffi::SomeFlags::FLAG_A & ffi::SomeFlags::FLAG_B;
1151+
assert_eq!(anb.0, 0x0);
1152+
}
1153+
};
1154+
do_run_test_manual("", hdr, rs, None, None).unwrap();
1155+
}
1156+
1157+
#[test]
1158+
fn test_newtype_enum() {
1159+
let hdr = indoc! {"
1160+
#include <cstdint>
1161+
enum SomeFlags : int {
1162+
FLAG_A = 1 << 0, // 0x1
1163+
FLAG_B = 1 << 2, // 0x4
1164+
FLAG_C = FLAG_A | FLAG_B, // 0x5
1165+
};
1166+
"};
1167+
let hexathorpe = Token![#](Span::call_site());
1168+
let rs = quote! {
1169+
use autocxx::prelude::*;
1170+
include_cpp! {
1171+
#hexathorpe include "input.h"
1172+
safety!(unsafe_ffi)
1173+
enum_style!(NewtypeEnum, "SomeFlags")
1174+
generate_pod!("SomeFlags")
1175+
}
1176+
1177+
fn main() {
1178+
let a = ffi::SomeFlags::FLAG_A;
1179+
let b = ffi::SomeFlags::FLAG_B;
1180+
let c = ffi::SomeFlags::FLAG_C;
1181+
assert_eq!(a.0, 0x1);
1182+
assert_eq!(b.0, 0x4);
1183+
assert_eq!(c.0, 0x5);
1184+
}
1185+
};
1186+
do_run_test_manual("", hdr, rs, None, None).unwrap();
1187+
}
1188+
1189+
#[test]
1190+
fn test_rustified_enum() {
1191+
let hdr = indoc! {"
1192+
enum Bob {
1193+
BOB_VALUE_1,
1194+
BOB_VALUE_2,
1195+
};
1196+
"};
1197+
let hexathorpe = Token![#](Span::call_site());
1198+
let rs = quote! {
1199+
use autocxx::prelude::*;
1200+
include_cpp! {
1201+
#hexathorpe include "input.h"
1202+
safety!(unsafe_ffi)
1203+
enum_style!(RustifiedEnum, "Bob")
1204+
generate_pod!("Bob")
1205+
}
1206+
1207+
fn main() {
1208+
let a = ffi::Bob::BOB_VALUE_1;
1209+
let b = ffi::Bob::BOB_VALUE_2;
1210+
assert!(a != b);
1211+
}
1212+
};
1213+
do_run_test_manual("", hdr, rs, None, None).unwrap();
1214+
}
1215+
1216+
#[test]
1217+
fn test_rustified_nonexhaustive_enum() {
1218+
let hdr = indoc! {"
1219+
enum Bob {
1220+
BOB_VALUE_1,
1221+
BOB_VALUE_2,
1222+
};
1223+
"};
1224+
let hexathorpe = Token![#](Span::call_site());
1225+
let rs = quote! {
1226+
use autocxx::prelude::*;
1227+
include_cpp! {
1228+
#hexathorpe include "input.h"
1229+
safety!(unsafe_ffi)
1230+
enum_style!(RustifiedEnum, "Bob")
1231+
generate_pod!("Bob")
1232+
}
1233+
1234+
fn main() {
1235+
let a = ffi::Bob::BOB_VALUE_1;
1236+
let b = ffi::Bob::BOB_VALUE_2;
1237+
assert!(a != b);
1238+
}
1239+
};
1240+
do_run_test_manual("", hdr, rs, None, None).unwrap();
1241+
}
1242+
1243+
#[test]
1244+
fn test_several_enums() {
1245+
let hdr = indoc! {"
1246+
enum First : int {
1247+
FIRST_A = 5,
1248+
FIRST_B = 6
1249+
};
1250+
enum Second {
1251+
SECOND_A,
1252+
SECOND_B
1253+
};
1254+
enum Default : int {
1255+
DEFAULT_A = 1 << 1,
1256+
DEFAULT_B = 1 << 3
1257+
};
1258+
enum Newtype {
1259+
NEWTYPE_A,
1260+
NEWTYPE_B
1261+
};
1262+
"};
1263+
let hexathorpe = Token![#](Span::call_site());
1264+
let rs = quote! {
1265+
use autocxx::prelude::*;
1266+
include_cpp! {
1267+
#hexathorpe include "input.h"
1268+
safety!(unsafe_ffi)
1269+
enum_style!(BitfieldEnum, "First", "Second")
1270+
enum_style!(NewtypeEnum, "Newtype")
1271+
generate_pod!("First")
1272+
generate_pod!("Second")
1273+
generate_pod!("Newtype")
1274+
generate!("Default")
1275+
}
1276+
1277+
fn main() {
1278+
let first_a = ffi::First::FIRST_A;
1279+
let first_b = ffi::First::FIRST_B;
1280+
assert_eq!((first_a & first_b).0, 0x4);
1281+
let second_a = ffi::Second::SECOND_A;
1282+
let second_b = ffi::Second::SECOND_B;
1283+
assert_eq!((second_a | second_b).0, 0x1);
1284+
assert!(ffi::Default::DEFAULT_A != ffi::Default::DEFAULT_B);
1285+
assert!(ffi::Newtype::NEWTYPE_A != ffi::Newtype::NEWTYPE_B);
1286+
}
1287+
};
1288+
do_run_test_manual("", hdr, rs, None, None).unwrap();
1289+
}
1290+
11181291
#[test]
11191292
fn test_re_export() {
11201293
let cxx = indoc! {"

parser/src/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use syn::{
2525
use syn::{Ident, Result as ParseResult};
2626
use thiserror::Error;
2727

28+
use crate::enum_style::EnumStyleMap;
2829
use crate::{directives::get_directives, RustPath};
2930

3031
use quote::quote;
@@ -228,6 +229,7 @@ pub struct IncludeCppConfig {
228229
pub concretes: ConcretesMap,
229230
pub externs: ExternCppTypeMap,
230231
pub opaquelist: Vec<String>,
232+
pub enum_styles: EnumStyleMap,
231233
}
232234

233235
impl Parse for IncludeCppConfig {
@@ -384,6 +386,10 @@ impl IncludeCppConfig {
384386
self.constructor_blocklist.contains(&cpp_name.to_string())
385387
}
386388

389+
pub fn get_enums(&self) -> HashSet<&String> {
390+
self.enum_styles.get_enum_names()
391+
}
392+
387393
pub fn get_blocklist(&self) -> impl Iterator<Item = &String> {
388394
self.blocklist.iter()
389395
}

parser/src/directives.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::config::AllowlistErr;
2424
use crate::config::Allowlist;
2525

2626
use crate::directive_names::{EXTERN_RUST_FUN, EXTERN_RUST_TYPE, SUBCLASS};
27+
use crate::enum_style::EnumStyleMap;
2728
use crate::{AllowlistEntry, IncludeCppConfig};
2829
use crate::{ParseResult, RustFun, RustPath};
2930

@@ -114,6 +115,13 @@ pub(crate) fn get_directives() -> &'static DirectivesMap {
114115
"extern_cpp_opaque_type".into(),
115116
Box::new(ExternCppType { opaque: true }),
116117
);
118+
need_exclamation.insert(
119+
"enum_style".into(),
120+
Box::new(EnumStyle(
121+
|config| &mut config.enum_styles,
122+
|config| &config.enum_styles,
123+
)),
124+
);
117125

118126
DirectivesMap {
119127
need_hexathorpe,
@@ -567,3 +575,51 @@ impl Directive for ExternCppType {
567575
)
568576
}
569577
}
578+
579+
struct EnumStyle<SET, GET>(SET, GET)
580+
where
581+
SET: Fn(&mut IncludeCppConfig) -> &mut EnumStyleMap,
582+
GET: Fn(&IncludeCppConfig) -> &EnumStyleMap;
583+
584+
impl<SET, GET> Directive for EnumStyle<SET, GET>
585+
where
586+
SET: Fn(&mut IncludeCppConfig) -> &mut EnumStyleMap + Sync + Send,
587+
GET: Fn(&IncludeCppConfig) -> &EnumStyleMap + Sync + Send,
588+
{
589+
fn parse(
590+
&self,
591+
args: ParseStream,
592+
config: &mut IncludeCppConfig,
593+
_ident_span: &Span,
594+
) -> ParseResult<()> {
595+
let style: crate::EnumStyle = args.parse()?;
596+
args.parse::<syn::token::Comma>()?;
597+
let litstrs: syn::punctuated::Punctuated<syn::LitStr, syn::token::Comma> =
598+
syn::punctuated::Punctuated::parse_separated_nonempty(args)?;
599+
let enums = litstrs.into_iter().map(|s| s.value());
600+
601+
config
602+
.enum_styles
603+
.0
604+
.entry(style)
605+
.or_insert_with(Vec::new)
606+
.extend(enums);
607+
Ok(())
608+
}
609+
610+
#[cfg(feature = "reproduction_case")]
611+
fn output<'a>(
612+
&self,
613+
config: &'a IncludeCppConfig,
614+
) -> Box<dyn Iterator<Item = TokenStream> + 'a> {
615+
Box::new(config.enum_styles.0.iter().map(|(style, enums)| {
616+
let lits: Vec<syn::LitStr> = enums
617+
.iter()
618+
.map(|s| syn::LitStr::new(s, Span::call_site()))
619+
.collect();
620+
quote! {
621+
#(#lits),* , #style
622+
}
623+
}))
624+
}
625+
}

0 commit comments

Comments
 (0)