Support enums defined in C++ code.

This allows listing an enum in an extern "C" block as well as in the
shared block.  In this case, we do not emit the C++ declaration of the
enum but instead emit static assertions that it has the values that we
expect.
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 8ce3813..2ea6ca8 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -5,7 +5,7 @@
 use crate::syntax::symbol::Symbol;
 use crate::syntax::{mangle, Api, Enum, ExternFn, ExternType, Signature, Struct, Type, Types, Var};
 use proc_macro2::Ident;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
 pub(super) fn gen(
     namespace: &Namespace,
@@ -46,6 +46,7 @@
         }
     }
 
+    let mut cxx_types = HashSet::new();
     let mut methods_for_type = HashMap::new();
     for api in apis {
         if let Api::RustFunction(efn) = api {
@@ -56,6 +57,9 @@
                     .push(efn);
             }
         }
+        if let Api::CxxType(enm) = api {
+            cxx_types.insert(&enm.ident);
+        }
     }
 
     for api in apis {
@@ -66,7 +70,11 @@
             }
             Api::Enum(enm) => {
                 out.next_section();
-                write_enum(out, enm);
+                if cxx_types.contains(&enm.ident) {
+                    check_enum(out, enm);
+                } else {
+                    write_enum(out, enm);
+                }
             }
             Api::RustType(ety) => {
                 if let Some(methods) = methods_for_type.get(&ety.ident) {
@@ -373,6 +381,34 @@
     writeln!(out, "}};");
 }
 
+fn check_enum(out: &mut OutFile, enm: &Enum) {
+    let discriminants = enm
+        .variants
+        .iter()
+        .scan(None, |prev_discriminant, variant| {
+            let discriminant = variant
+                .discriminant
+                .unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
+            *prev_discriminant = Some(discriminant);
+            Some(discriminant)
+        });
+    writeln!(
+        out,
+        "static_assert(sizeof({}) == sizeof(uint32_t));",
+        enm.ident
+    );
+    enm.variants
+        .iter()
+        .zip(discriminants)
+        .for_each(|(variant, discriminant)| {
+            writeln!(
+                out,
+                "static_assert({}::{} == {});",
+                enm.ident, variant.ident, discriminant
+            );
+        });
+}
+
 fn write_exception_glue(out: &mut OutFile, apis: &[Api]) {
     let mut has_cxx_throws = false;
     for api in apis {