From 6a9066f7cd7f7decf25b4d19c5f41bb99cdf08da Mon Sep 17 00:00:00 2001 From: Evan Shaw Date: Sun, 29 Dec 2019 18:39:12 +1300 Subject: [PATCH] Add enum_class option This option allows specifying that a C++ enum should be emitted with plain `enum` rather than `enum class`. It's true that `enum class` should generally be preferred, but sometimes there's existing code which is already using plain `enum`, and porting that code to Rust becomes easier when `cbindgen` can emit plain `enum`. This option can be overridden on a per-enum basis using a `cbindgen:` annotation. It defaults to true for two reasons: * Backward compatibility. * `enum class` is probably actually what you want, in general. --- docs.md | 5 ++++ src/bindgen/config.rs | 31 +++++++++++++++++++++- src/bindgen/ir/enumeration.rs | 6 ++++- template.toml | 1 + tests/expectations/both/enum.c | 32 +++++++++++++++++++++- tests/expectations/both/enum.compat.c | 38 ++++++++++++++++++++++++++- tests/expectations/enum.c | 32 +++++++++++++++++++++- tests/expectations/enum.compat.c | 38 ++++++++++++++++++++++++++- tests/expectations/enum.cpp | 31 +++++++++++++++++++++- tests/expectations/tag/enum.c | 21 +++++++++++++-- tests/expectations/tag/enum.compat.c | 27 +++++++++++++++++-- tests/rust/enum.rs | 22 +++++++++++++++- 12 files changed, 272 insertions(+), 12 deletions(-) diff --git a/docs.md b/docs.md index ad18d4035..725e31af3 100644 --- a/docs.md +++ b/docs.md @@ -269,6 +269,7 @@ The rest are just local overrides for the same options found in the cbindgen.tom * derive-mut-casts * derive-tagged-enum-destructor * derive-tagged-enum-copy-constructor +* enum-class * prefix-with-name * private-default-tagged-enum-constructor @@ -672,6 +673,10 @@ add_sentinel = false # default: false prefix_with_name = false +# Whether to emit enums using "enum class" when targeting C++. +# default: true +enum_class = true + # Whether to generate static `::MyVariant(..)` constructors and `bool IsMyVariant()` # methods for enums with fields. # diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index aad37054b..620963afd 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -391,7 +391,7 @@ impl StructConfig { } /// Settings to apply to generated enums. -#[derive(Debug, Clone, Default, Deserialize)] +#[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] #[serde(deny_unknown_fields)] #[serde(default)] @@ -425,11 +425,34 @@ pub struct EnumConfig { /// This is only generated if a copy constructor for the same tagged enum is /// generated as well. pub derive_tagged_enum_copy_assignment: bool, + /// Declare the enum as an enum class. + /// Only relevant when targeting C++. + pub enum_class: bool, /// Whether to generate empty, private default-constructors for tagged /// enums. pub private_default_tagged_enum_constructor: bool, } +impl Default for EnumConfig { + fn default() -> EnumConfig { + EnumConfig { + rename_variants: None, + add_sentinel: false, + prefix_with_name: false, + derive_helper_methods: false, + derive_const_casts: false, + derive_mut_casts: false, + cast_assert_name: None, + must_use: None, + derive_tagged_enum_destructor: false, + derive_tagged_enum_copy_constructor: false, + derive_tagged_enum_copy_assignment: false, + enum_class: true, + private_default_tagged_enum_constructor: false, + } + } +} + impl EnumConfig { pub(crate) fn add_sentinel(&self, annotations: &AnnotationSet) -> bool { if let Some(x) = annotations.bool("add-sentinel") { @@ -473,6 +496,12 @@ impl EnumConfig { } self.derive_tagged_enum_copy_assignment } + pub(crate) fn enum_class(&self, annotations: &AnnotationSet) -> bool { + if let Some(x) = annotations.bool("enum-class") { + return x; + } + self.enum_class + } pub(crate) fn private_default_tagged_enum_constructor( &self, annotations: &AnnotationSet, diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 023a3d4a1..8592d5f27 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -559,7 +559,11 @@ impl Source for Enum { } } } else { - out.write("enum class"); + if config.enumeration.enum_class(&self.annotations) { + out.write("enum class"); + } else { + out.write("enum"); + } if self.annotations.must_use { if let Some(ref anno) = config.enumeration.must_use { diff --git a/template.toml b/template.toml index 52a3515c1..997ded362 100644 --- a/template.toml +++ b/template.toml @@ -103,6 +103,7 @@ derive_mut_casts = false # cast_assert_name = "ASSERT" derive_tagged_enum_destructor = false derive_tagged_enum_copy_constructor = false +enum_class = true private_default_tagged_enum_constructor = false diff --git a/tests/expectations/both/enum.c b/tests/expectations/both/enum.c index 6f8212922..365439e28 100644 --- a/tests/expectations/both/enum.c +++ b/tests/expectations/both/enum.c @@ -65,6 +65,21 @@ enum M { }; typedef int8_t M; +typedef enum N { + n1, + n2, + n3, + n4, +} N; + +enum O { + o1, + o2, + o3, + o4, +}; +typedef int8_t O; + typedef struct J J; typedef struct K K; @@ -142,4 +157,19 @@ typedef struct I { }; } I; -void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m); +void root(Opaque *opaque, + A a, + B b, + C c, + D d, + E e, + F f, + G g, + H h, + I i, + J j, + K k, + L l, + M m, + N n, + O o); diff --git a/tests/expectations/both/enum.compat.c b/tests/expectations/both/enum.compat.c index adbdef854..f899fd69c 100644 --- a/tests/expectations/both/enum.compat.c +++ b/tests/expectations/both/enum.compat.c @@ -107,6 +107,27 @@ enum M typedef int8_t M; #endif // __cplusplus +typedef enum N { + n1, + n2, + n3, + n4, +} N; + +enum O +#ifdef __cplusplus + : int8_t +#endif // __cplusplus + { + o1, + o2, + o3, + o4, +}; +#ifndef __cplusplus +typedef int8_t O; +#endif // __cplusplus + typedef struct J J; typedef struct K K; @@ -200,7 +221,22 @@ typedef struct I { extern "C" { #endif // __cplusplus -void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m); +void root(Opaque *opaque, + A a, + B b, + C c, + D d, + E e, + F f, + G g, + H h, + I i, + J j, + K k, + L l, + M m, + N n, + O o); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/enum.c b/tests/expectations/enum.c index d3b105d1d..48eb93450 100644 --- a/tests/expectations/enum.c +++ b/tests/expectations/enum.c @@ -65,6 +65,21 @@ enum M { }; typedef int8_t M; +typedef enum { + n1, + n2, + n3, + n4, +} N; + +enum O { + o1, + o2, + o3, + o4, +}; +typedef int8_t O; + typedef struct J J; typedef struct K K; @@ -142,4 +157,19 @@ typedef struct { }; } I; -void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m); +void root(Opaque *opaque, + A a, + B b, + C c, + D d, + E e, + F f, + G g, + H h, + I i, + J j, + K k, + L l, + M m, + N n, + O o); diff --git a/tests/expectations/enum.compat.c b/tests/expectations/enum.compat.c index f735748e1..2025a2589 100644 --- a/tests/expectations/enum.compat.c +++ b/tests/expectations/enum.compat.c @@ -107,6 +107,27 @@ enum M typedef int8_t M; #endif // __cplusplus +typedef enum { + n1, + n2, + n3, + n4, +} N; + +enum O +#ifdef __cplusplus + : int8_t +#endif // __cplusplus + { + o1, + o2, + o3, + o4, +}; +#ifndef __cplusplus +typedef int8_t O; +#endif // __cplusplus + typedef struct J J; typedef struct K K; @@ -200,7 +221,22 @@ typedef struct { extern "C" { #endif // __cplusplus -void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m); +void root(Opaque *opaque, + A a, + B b, + C c, + D d, + E e, + F f, + G g, + H h, + I i, + J j, + K k, + L l, + M m, + N n, + O o); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/enum.cpp b/tests/expectations/enum.cpp index 0ae9d7aee..d39fa56ed 100644 --- a/tests/expectations/enum.cpp +++ b/tests/expectations/enum.cpp @@ -58,6 +58,20 @@ enum class M : int8_t { m3 = 1, }; +enum N { + n1, + n2, + n3, + n4, +}; + +enum O : int8_t { + o1, + o2, + o3, + o4, +}; + struct J; struct K; @@ -137,6 +151,21 @@ struct I { extern "C" { -void root(Opaque *o, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m); +void root(Opaque *opaque, + A a, + B b, + C c, + D d, + E e, + F f, + G g, + H h, + I i, + J j, + K k, + L l, + M m, + N n, + O o); } // extern "C" diff --git a/tests/expectations/tag/enum.c b/tests/expectations/tag/enum.c index 51611c522..d98f505e7 100644 --- a/tests/expectations/tag/enum.c +++ b/tests/expectations/tag/enum.c @@ -65,6 +65,21 @@ enum M { }; typedef int8_t M; +enum N { + n1, + n2, + n3, + n4, +}; + +enum O { + o1, + o2, + o3, + o4, +}; +typedef int8_t O; + struct J; struct K; @@ -142,7 +157,7 @@ struct I { }; }; -void root(struct Opaque *o, +void root(struct Opaque *opaque, A a, B b, C c, @@ -155,4 +170,6 @@ void root(struct Opaque *o, struct J j, struct K k, enum L l, - M m); + M m, + enum N n, + O o); diff --git a/tests/expectations/tag/enum.compat.c b/tests/expectations/tag/enum.compat.c index 8e0724f71..7b2e42603 100644 --- a/tests/expectations/tag/enum.compat.c +++ b/tests/expectations/tag/enum.compat.c @@ -107,6 +107,27 @@ enum M typedef int8_t M; #endif // __cplusplus +enum N { + n1, + n2, + n3, + n4, +}; + +enum O +#ifdef __cplusplus + : int8_t +#endif // __cplusplus + { + o1, + o2, + o3, + o4, +}; +#ifndef __cplusplus +typedef int8_t O; +#endif // __cplusplus + struct J; struct K; @@ -200,7 +221,7 @@ struct I { extern "C" { #endif // __cplusplus -void root(struct Opaque *o, +void root(struct Opaque *opaque, A a, B b, C c, @@ -213,7 +234,9 @@ void root(struct Opaque *o, struct J j, struct K k, enum L l, - M m); + M m, + enum N n, + O o); #ifdef __cplusplus } // extern "C" diff --git a/tests/rust/enum.rs b/tests/rust/enum.rs index d15d6e90c..c98e5df3c 100644 --- a/tests/rust/enum.rs +++ b/tests/rust/enum.rs @@ -103,9 +103,27 @@ enum M { m3 = 1, } +/// cbindgen:enum-class=false +#[repr(C)] +enum N { + n1, + n2, + n3, + n4, +} + +/// cbindgen:enum-class=false +#[repr(i8)] +enum O { + o1, + o2, + o3, + o4, +} + #[no_mangle] pub extern "C" fn root( - o: *mut Opaque, + opaque: *mut Opaque, a: A, b: B, c: C, @@ -119,5 +137,7 @@ pub extern "C" fn root( k: K, l: L, m: M, + n: N, + o: O, ) { }