Skip to content

Commit 7467f6c

Browse files
committed
enums as structs
1 parent ca48925 commit 7467f6c

File tree

7 files changed

+193
-0
lines changed

7 files changed

+193
-0
lines changed

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: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,46 @@ fn test_enum_with_funcs() {
11151115
run_test(cxx, hdr, rs, &["Bob", "give_bob"], &[]);
11161116
}
11171117

1118+
#[test]
1119+
fn test_enum_with_associated_consts() {
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+
//enum_style!(RustifiedEnum, "SomeFlags")
1136+
generate!("SomeFlags")
1137+
}
1138+
1139+
fn main() {
1140+
let a = ffi::SomeFlags::FLAG_A;
1141+
/*let b = ffi::SomeFlags::FLAG_B;
1142+
let c = ffi::SomeFlags::FLAG_C;
1143+
assert_eq!(a.0, 0x1);
1144+
assert_eq!(b.0, 0x4);
1145+
assert_eq!(c.0, 0x5);
1146+
1147+
let aob = ffi::SomeFlags::FLAG_A | ffi::SomeFlags::FLAG_B;
1148+
assert_eq!(aob.0, 0x5);
1149+
assert_eq!(aob.0, ffi::SomeFlags::FLAG_C.0);
1150+
1151+
let anb = ffi::SomeFlags::FLAG_A & ffi::SomeFlags::FLAG_B;
1152+
assert_eq!(anb.0, 0x0);*/
1153+
}
1154+
};
1155+
do_run_test_manual("", hdr, rs, None, None).unwrap();
1156+
}
1157+
11181158
#[test]
11191159
fn test_re_export() {
11201160
let cxx = indoc! {"

parser/src/config.rs

Lines changed: 2 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 {

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+
}

parser/src/enum_style.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use proc_macro2::{Ident, Span};
2+
use quote::{quote, ToTokens};
3+
use std::collections::HashMap;
4+
use syn::parse::Parse;
5+
6+
#[derive(Debug, Hash, PartialEq, Eq)]
7+
pub enum EnumStyle {
8+
BitfieldEnum,
9+
NewtypeEnum,
10+
NewtypeGlobalEnum,
11+
RustifiedEnum,
12+
RustifiedNonExhaustiveEnum,
13+
ConstifiedEnumModule,
14+
ConstifiedEnum,
15+
}
16+
17+
#[derive(Debug, Default)]
18+
pub struct EnumStyleMap(pub HashMap<EnumStyle, Vec<String>>);
19+
20+
impl std::hash::Hash for EnumStyleMap {
21+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
22+
for (k, v) in &self.0 {
23+
k.hash(state);
24+
v.hash(state);
25+
}
26+
}
27+
}
28+
29+
impl EnumStyle {
30+
fn from_str(s: &str) -> Option<Self> {
31+
use EnumStyle::*;
32+
Some(match s {
33+
"BitfieldEnum" => BitfieldEnum,
34+
"NewtypeEnum" => NewtypeEnum,
35+
"NewtypeGlobalEnum" => NewtypeGlobalEnum,
36+
"RustifiedEnum" => RustifiedEnum,
37+
"RustifiedNonExhaustiveEnum" => RustifiedNonExhaustiveEnum,
38+
"ConstifiedEnumModule" => ConstifiedEnumModule,
39+
"ConstifiedEnum" => ConstifiedEnum,
40+
_ => return None,
41+
})
42+
}
43+
}
44+
45+
impl Parse for EnumStyle {
46+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
47+
let style_ident: Ident = input.parse()?;
48+
let style = style_ident.to_string();
49+
EnumStyle::from_str(&style).ok_or(syn::Error::new(
50+
style_ident.span(),
51+
format!("unknown enum style `{}`", style),
52+
))
53+
}
54+
}
55+
56+
impl ToTokens for EnumStyle {
57+
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
58+
use EnumStyle::*;
59+
let variant_ident = match self {
60+
BitfieldEnum => "BitfieldEnum",
61+
NewtypeEnum => "NewtypeEnum",
62+
NewtypeGlobalEnum => "NewtypeGlobalEnum",
63+
RustifiedEnum => "RustifiedEnum",
64+
RustifiedNonExhaustiveEnum => "RustifiedNonExhaustiveEnum",
65+
ConstifiedEnumModule => "ConstifiedEnumModule",
66+
ConstifiedEnum => "ConstifiedEnum",
67+
};
68+
let var = Ident::new(variant_ident, Span::call_site());
69+
tokens.extend(quote! { #var });
70+
}
71+
}

parser/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ pub mod file_locations;
1414
mod multi_bindings;
1515
mod path;
1616
mod subclass_attrs;
17+
mod enum_style;
1718

1819
pub use config::{
1920
AllowlistEntry, ExternCppType, IncludeCppConfig, RustFun, Subclass, UnsafePolicy,
2021
};
22+
pub use enum_style::EnumStyle;
2123
use file_locations::FileLocationStrategy;
2224
pub use multi_bindings::{MultiBindings, MultiBindingsErr};
2325
pub use path::RustPath;

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,12 @@ macro_rules! subclass {
402402
($($tt:tt)*) => { $crate::usage!{$($tt)*} };
403403
}
404404

405+
/// TODO
406+
#[macro_export]
407+
macro_rules! enum_style {
408+
($($tt:tt)*) => { $crate::usage!{$($tt)*} };
409+
}
410+
405411
/// Indicates that a C++ type can definitely be instantiated. This has effect
406412
/// only in a very specific case:
407413
/// * the type is a typedef to something else

0 commit comments

Comments
 (0)