Remove Features methods
diff --git a/codegen/src/gen.rs b/codegen/src/gen.rs
index 83ddc4e..a51a800 100644
--- a/codegen/src/gen.rs
+++ b/codegen/src/gen.rs
@@ -355,7 +355,7 @@
             types::Type::Group(t) => Some(token_group_visit(&t[..], kind, name)),
             types::Type::Syn(t) => {
                 fn requires_full(features: &types::Features) -> bool {
-                    features.contains("full") && features.len() == 1
+                    features.any.contains("full") && features.any.len() == 1
                 }
 
                 let mut res = simple_visit(t, kind, name);
@@ -380,17 +380,11 @@
     }
 
     fn visit_features(features: &types::Features) -> TokenStream {
+        let features = &features.any;
         match features.len() {
             0 => quote!(),
-            1 => {
-                let feature = &features[0];
-                quote!(#[cfg(feature = #feature)])
-            }
-            _ => {
-                let features = features.iter().map(|feature| quote!(feature = #feature));
-
-                quote!(#[cfg(any( #(#features),* ))])
-            }
+            1 => quote!(#[cfg(feature = #(#features)*)]),
+            _ => quote!(#[cfg(any(#(feature = #features),*))]),
         }
     }
 
diff --git a/codegen/src/parse.rs b/codegen/src/parse.rs
index 448188d..cdfc7e0 100644
--- a/codegen/src/parse.rs
+++ b/codegen/src/parse.rs
@@ -192,7 +192,15 @@
         }
 
         let features: types::Features = syn::parse2(attr.tts.clone()).unwrap();
-        ret.join(&features);
+
+        if ret.any.is_empty() {
+            ret = features;
+        } else if ret.any.len() < features.any.len() {
+            assert!(ret.any.iter().all(|f| features.any.contains(f)));
+        } else {
+            assert!(features.any.iter().all(|f| ret.any.contains(f)));
+            ret = features;
+        }
     }
 
     ret
@@ -248,7 +256,7 @@
     use syn::parse::{Parse, ParseStream, Result};
     use syn::*;
 
-    use std::collections::BTreeMap;
+    use std::collections::{BTreeMap, BTreeSet};
 
     fn peek_tag(input: ParseStream, tag: &str) -> bool {
         let ahead = input.fork();
@@ -445,7 +453,7 @@
 
     impl Parse for types::Features {
         fn parse(input: ParseStream) -> Result<Self> {
-            let mut features = vec![];
+            let mut features = BTreeSet::new();
 
             let level_1;
             parenthesized!(level_1 in input);
@@ -459,14 +467,14 @@
                 parenthesized!(level_2 in level_1);
 
                 while !level_2.is_empty() {
-                    features.push(parse_feature(&level_2)?);
+                    features.insert(parse_feature(&level_2)?);
 
                     if !level_2.is_empty() {
                         level_2.parse::<Token![,]>()?;
                     }
                 }
             } else if i == "feature" {
-                features.push(parse_feature(&level_1)?);
+                features.insert(parse_feature(&level_1)?);
                 assert!(level_1.is_empty());
             } else {
                 panic!("{:?}", i);
diff --git a/codegen/src/types.rs b/codegen/src/types.rs
index cc6733c..7be3487 100644
--- a/codegen/src/types.rs
+++ b/codegen/src/types.rs
@@ -1,8 +1,7 @@
 use indexmap::IndexMap;
 use serde::{Deserialize, Deserializer};
 
-use std::collections::BTreeMap;
-use std::ops;
+use std::collections::{BTreeMap, BTreeSet};
 
 #[derive(Debug, Clone, PartialEq)]
 pub struct Definitions {
@@ -73,41 +72,7 @@
 
 #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
 pub struct Features {
-    pub any: Vec<String>,
-}
-
-impl Features {
-    pub fn join(&mut self, other: &Features) {
-        if self.any.is_empty() {
-            self.any = other.any.clone();
-        } else if self.any.len() < other.any.len() {
-            assert!(self.any.iter().all(|f| other.any.contains(f)));
-        } else {
-            assert!(other.any.iter().all(|f| self.any.contains(f)));
-
-            self.any = other.any.clone();
-        }
-    }
-
-    pub fn len(&self) -> usize {
-        self.any.len()
-    }
-
-    pub fn contains(&self, tag: &str) -> bool {
-        self.iter().any(|s| s == tag)
-    }
-
-    pub fn iter(&self) -> impl Iterator<Item = &str> {
-        self.any.iter().map(|s| &s[..])
-    }
-}
-
-impl ops::Index<usize> for Features {
-    type Output = str;
-
-    fn index(&self, index: usize) -> &str {
-        self.any.index(index)
-    }
+    pub any: BTreeSet<String>,
 }
 
 fn is_private(data: &Data) -> bool {