Repository: dtolnay/cxx (rust)

Issue:
Expose enum value as integer
#170 produces "enums" with a private integer representation, and public associated constants corresponding to the variants.

```rust
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub enum SmallPrime(u32);

#[allow(non_upper_case_globals)]
impl SmallPrime {
    pub const Two: Self = SmallPrime(2);
    pub const Three: Self = SmallPrime(3);
    pub const Five: Self = SmallPrime(6);
}
```

This behaves like an ordinary Rust enum in all ways except that it enforces a wildcard match arm when matched (which is deliberate) and that it cannot be cast using `as` to a primitive (which is unfortunate).

We should expose some way to get the primitive value. Maybe a method, maybe just a straightforward public field like `n.repr`.

Pull request description:
Expose the enum value to Rust as a field
Fixes #178.

Patch:
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index a3c8d1a2..19cde4f1 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -137,14 +137,16 @@ fn expand_enum(enm: &Enum) -> TokenStream {
                 .unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
             *prev_discriminant = Some(discriminant);
             Some(quote! {
-                pub const #variant_ident: Self = #ident(#discriminant);
+                pub const #variant_ident: Self = #ident { repr: #discriminant };
             })
         });
     quote! {
         #doc
         #[derive(Copy, Clone, PartialEq, Eq)]
         #[repr(transparent)]
-        pub struct #ident(u32);
+        pub struct #ident {
+            pub repr: u32,
+        }
 
         #[allow(non_upper_case_globals)]
         impl #ident {


Test patch:
diff --git a/tests/test.rs b/tests/test.rs
index 1156d5d0..b8593c58 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -52,15 +52,15 @@ fn test_c_return() {
     assert_eq!(2020, ffi::c_return_identity(2020));
     assert_eq!(2021, ffi::c_return_sum(2020, 1));
     match ffi::c_return_enum(0) {
-        ffi::Enum::AVal => {}
+        enm @ ffi::Enum::AVal => assert_eq!(0, enm.repr),
         _ => assert!(false),
     }
     match ffi::c_return_enum(1) {
-        ffi::Enum::BVal => {}
+        enm @ ffi::Enum::BVal => assert_eq!(2020, enm.repr),
         _ => assert!(false),
     }
     match ffi::c_return_enum(2021) {
-        ffi::Enum::CVal => {}
+        enm @ ffi::Enum::CVal => assert_eq!(2021, enm.repr),
         _ => assert!(false),
     }
 }
@@ -160,6 +160,13 @@ fn test_c_method_calls() {
     assert_eq!(old_value, unique_ptr.get2())
 }
 
+#[test]
+fn test_enum_representations() {
+    assert_eq!(0, ffi::Enum::AVal.repr);
+    assert_eq!(2020, ffi::Enum::BVal.repr);
+    assert_eq!(2021, ffi::Enum::CVal.repr);
+}
+
 #[no_mangle]
 extern "C" fn cxx_test_suite_get_box() -> *mut cxx_test_suite::R {
     Box::into_raw(Box::new(2020usize))
diff --git a/tests/ui/enum_match_without_wildcard.stderr b/tests/ui/enum_match_without_wildcard.stderr
index 12b8429f..93a89572 100644
--- a/tests/ui/enum_match_without_wildcard.stderr
+++ b/tests/ui/enum_match_without_wildcard.stderr
@@ -1,11 +1,11 @@
-error[E0004]: non-exhaustive patterns: `A(2u32..=std::u32::MAX)` not covered
+error[E0004]: non-exhaustive patterns: `A { repr: 2u32..=std::u32::MAX }` not covered
   --> $DIR/enum_match_without_wildcard.rs:12:11
    |
 1  | #[cxx::bridge]
    | -------------- `ffi::A` defined here
 ...
 12 |     match a {
-   |           ^ pattern `A(2u32..=std::u32::MAX)` not covered
+   |           ^ pattern `A { repr: 2u32..=std::u32::MAX }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `ffi::A`