+/// Decodes the custom attributes for our custom derive.
+#[derive(FromDeriveInput, Default)]
+#[darling(attributes(enumset), default)]
+struct EnumsetAttrs {
+ no_ops: bool,
+ serialize_as_list: bool,
+ serialize_deny_unknown: bool,
+ #[darling(default)]
+ serialize_repr: Option<String>,
+}
+
+/// An variant in the enum set type.
+struct EnumSetValue {
+ name: Ident,
+ variant_repr: u32,
+}
+
+/// Stores information about the enum set type.
+#[allow(dead_code)]
+struct EnumSetInfo {
+ name: Ident,
+ explicit_repr: Option<Ident>,
+ explicit_serde_repr: Option<Ident>,
+ has_signed_repr: bool,
+ has_large_repr: bool,
+ variants: Vec<EnumSetValue>,
+
+ max_discrim: u32,
+ cur_discrim: u32,
+ used_variant_names: HashSet<String>,
+ used_discriminators: HashSet<u32>,
+
+ no_ops: bool,
+ serialize_as_list: bool,
+ serialize_deny_unknown: bool,
+}
+impl EnumSetInfo {
+ fn new(input: &DeriveInput, attrs: EnumsetAttrs) -> EnumSetInfo {
+ EnumSetInfo {
+ name: input.ident.clone(),
+ explicit_repr: None,
+ explicit_serde_repr: attrs.serialize_repr.map(|x| Ident::new(&x, Span::call_site())),
+ has_signed_repr: false,
+ has_large_repr: false,
+ variants: Vec::new(),
+ max_discrim: 0,
+ cur_discrim: 0,
+ used_variant_names: HashSet::new(),
+ used_discriminators: HashSet::new(),
+ no_ops: attrs.no_ops,
+ serialize_as_list: attrs.serialize_as_list,
+ serialize_deny_unknown: attrs.serialize_deny_unknown
+ }
+ }
+
+ fn push_explicit_repr(&mut self, attr_span: Span, repr: &str) -> Result<()> {
+ if self.explicit_repr.is_some() {
+ error(attr_span, "Cannot duplicate #[repr(...)] annotations.")
+ } else {
+ self.explicit_repr = Some(Ident::new(match repr {
+ "Rust" | "C" => return Ok(()), // We assume default repr in these cases.
+ "u8" | "u16" | "u32" => repr,
+ "usize" | "u64" | "u128" => {
+ self.has_large_repr = true;
+ repr
+ }
+ "i8" | "i16" | "i32" => {
+ self.has_signed_repr = true;
+ repr
+ }
+ "isize" | "i64" | "i128" => {
+ self.has_signed_repr = true;
+ self.has_large_repr = true;
+ repr
+ }
+ _ => return error(attr_span, "Unsupported repr.")
+ }, Span::call_site()));
+ Ok(())
+ }
+ }
+ fn push_variant(&mut self, variant: &Variant) -> Result<()> {
+ if self.used_variant_names.contains(&variant.ident.to_string()) {
+ error(variant.span(), "Duplicated variant name.")
+ } else if let Fields::Unit = variant.fields {
+ if let Some((_, expr)) = &variant.discriminant {
+ let discriminant_fail_message = format!(
+ "Enum set discriminants must be `u32`s.{}",
+ if self.has_signed_repr || self.has_large_repr {
+ format!(
+ " ({} discrimiants are still unsupported with reprs that allow them.)",
+ if self.has_large_repr {
+ "larger"
+ } else if self.has_signed_repr {
+ "negative"
+ } else {
+ "larger or negative"
+ }
+ )
+ } else {
+ String::new()
+ },
+ );
+ if let Expr::Lit(ExprLit { lit: Lit::Int(i), .. }) = expr {
+ match i.base10_parse() {
+ Ok(val) => self.cur_discrim = val,
+ Err(_) => error(expr.span(), &discriminant_fail_message)?,
+ }
+ } else {
+ error(variant.span(), &discriminant_fail_message)?;
+ }
+ }
+
+ let discriminant = self.cur_discrim;
+ if discriminant >= 128 {
+ let message = if self.variants.len() <= 127 {
+ "`#[derive(EnumSetType)]` currently only supports discriminants up to 127."
+ } else {
+ "`#[derive(EnumSetType)]` currently only supports enums up to 128 variants."
+ };
+ error(variant.span(), message)?;
+ }
+
+ if self.used_discriminators.contains(&discriminant) {
+ error(variant.span(), "Duplicated enum discriminant.")?;
+ }
+
+ self.cur_discrim += 1;
+ if discriminant > self.max_discrim {
+ self.max_discrim = discriminant;
+ }
+ self.variants.push(EnumSetValue {
+ name: variant.ident.clone(),
+ variant_repr: discriminant,
+ });
+ self.used_variant_names.insert(variant.ident.to_string());
+ self.used_discriminators.insert(discriminant);
+
+ Ok(())
+ } else {
+ error(variant.span(), "`#[derive(EnumSetType)]` can only be used on fieldless enums.")
+ }
+ }
+ fn validate(&self) -> Result<()> {
+ if let Some(explicit_serde_repr) = &self.explicit_serde_repr {
+ let is_overflowed = match explicit_serde_repr.to_string().as_str() {
+ "u8" => self.max_discrim >= 8,
+ "u16" => self.max_discrim >= 16,
+ "u32" => self.max_discrim >= 32,
+ "u64" => self.max_discrim >= 64,
+ "u128" => self.max_discrim >= 128,
+ _ => error(
+ Span::call_site(),
+ "Only `u8`, `u16`, `u32`, `u64` and `u128` are supported for serde_repr."
+ )?,
+ };
+ if is_overflowed {
+ error(Span::call_site(), "serialize_repr cannot be smaller than bitset.")?;
+ }
+ }
+ Ok(())
+ }
+
+ fn enum_repr(&self) -> SynTokenStream {
+ if let Some(explicit_repr) = &self.explicit_repr {
+ quote! { #explicit_repr }
+ } else if self.max_discrim < 0x100 {
+ quote! { u8 }
+ } else if self.max_discrim < 0x10000 {
+ quote! { u16 }
+ } else {
+ quote! { u32 }
+ }
+ }
+ fn enumset_repr(&self) -> SynTokenStream {
+ if self.max_discrim <= 7 {
+ quote! { u8 }
+ } else if self.max_discrim <= 15 {
+ quote! { u16 }
+ } else if self.max_discrim <= 31 {
+ quote! { u32 }
+ } else if self.max_discrim <= 63 {
+ quote! { u64 }
+ } else if self.max_discrim <= 127 {
+ quote! { u128 }
+ } else {
+ panic!("max_variant > 127?")
+ }
+ }
+ #[cfg(feature = "serde")]
+ fn serde_repr(&self) -> SynTokenStream {
+ if let Some(serde_repr) = &self.explicit_serde_repr {
+ quote! { #serde_repr }
+ } else {
+ self.enumset_repr()
+ }
+ }
+
+ fn all_variants(&self) -> u128 {
+ let mut accum = 0u128;
+ for variant in &self.variants {
+ assert!(variant.variant_repr <= 127);
+ accum |= 1u128 << variant.variant_repr as u128;
+ }
+ accum
+ }
+}
+