Compute enum discriminant during parsing

This allows us to reuse the computation in multiple places later.
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 8bf0a4a..fc51ee9 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -5,6 +5,7 @@
     Struct, Ty1, Type, Var, Variant,
 };
 use quote::{format_ident, quote};
+use std::collections::HashSet;
 use syn::punctuated::Punctuated;
 use syn::{
     Abi, Error, Expr, ExprLit, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
@@ -96,16 +97,33 @@
 
     let doc = attrs::parse_doc(&item.attrs)?;
 
-    for variant in &item.variants {
-        match &variant.fields {
+    let mut variants = Vec::new();
+    let mut discriminants = HashSet::new();
+    let mut prev_discriminant = None;
+    for variant in item.variants {
+        match variant.fields {
             Fields::Unit => {}
             _ => {
                 return Err(Error::new_spanned(
                     variant,
                     "enums with data are not supported yet",
-                ))
+                ));
             }
         }
+        if variant.discriminant.is_none() && prev_discriminant.unwrap_or(0) == u32::MAX {
+            return Err(Error::new_spanned(variant, "overflowed on value"));
+        }
+        let discriminant =
+            parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
+        if !discriminants.insert(discriminant) {
+            let msg = format!("discriminant value `{}` already exists", discriminant);
+            return Err(Error::new_spanned(variant, msg));
+        }
+        variants.push(Variant {
+            ident: variant.ident,
+            discriminant: discriminant,
+        });
+        prev_discriminant = Some(discriminant);
     }
 
     Ok(Api::Enum(Enum {
@@ -113,30 +131,20 @@
         enum_token: item.enum_token,
         ident: item.ident,
         brace_token: item.brace_token,
-        variants: item
-            .variants
-            .into_iter()
-            .map(parse_variant)
-            .collect::<Result<_>>()?,
+        variants: variants,
     }))
 }
 
-fn parse_variant(variant: RustVariant) -> Result<Variant> {
+fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
     match &variant.discriminant {
-        None => Ok(Variant {
-            ident: variant.ident,
-            discriminant: None,
-        }),
+        None => Ok(None),
         Some((
             _,
             Expr::Lit(ExprLit {
                 lit: Lit::Int(n), ..
             }),
         )) => match n.base10_parse() {
-            Ok(val) => Ok(Variant {
-                ident: variant.ident,
-                discriminant: Some(val),
-            }),
+            Ok(val) => Ok(Some(val)),
             Err(_) => Err(Error::new_spanned(
                 variant,
                 "cannot parse enum discriminant as an integer",