Repository: Peternator7/strum (rust)

Issue:
EnumDiscriminants should inherit the repr of the enum they are derived from
The below example code will generate `VehicleDiscriminants` enum with `Car` and `Truck` variants but it will be `repr(usize)` instead of inheriting the `u8` repr of `Vehicle` additionally they will have the default enum representations (`Car = 0` and `Vehicle = 1` in this case)

```
// Custom discriminant tests
#[derive(EnumDiscriminants, Debug, PartialEq)]
#[strum_discriminants(derive(FromRepr))]
#[repr(u8)]
enum Vehicle {
    Car(CarModel) = 1,
    Truck(TruckModel) = 3,
}
```

I would have expected the above code to produce the following:
```
#[repr(u8)]
#[derive(FromRepr)]
enum VehicleDiscriminants {
    Car = 1,
    Truck = 3,
}
```

Pull request description:
EnumDiscriminant  inherits the repr and discriminant values
Would close #283

Since `FromRepr` also uses the `repr` attribute as well, I  attempted to centralize the parsing to retrieve it into `helpers/type_props.rs`. 

I don't have any prior experience working with proc macros or `syn` in general so feel free to give stylistic pointers in addition to feedback on the functionality itself

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index de1f1ba..993b915 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,20 @@
 # Changelog
 
+## 0.25.3 (strum_macros)
+
+Received a number of bug fix PR's.
+
+* [#300](https://github.com/Peternator7/strum/pull/300): Fixes EnumIter for enums named `Option`.
+* [#301](https://github.com/Peternator7/strum/pull/301): Improved doc comments
+* [#304](https://github.com/Peternator7/strum/pull/304): Removed some unused Vec's
+* [#305](https://github.com/Peternator7/strum/pull/305): Added generic support to `EnumIs`
+
+## 0.25.2 (strum_macros)
+
+* [#289](https://github.com/Peternator7/strum/pull/289): Enables a previously disabled rustdoc.
+* [#287](https://github.com/Peternator7/strum/pull/287): Fixes a bug in EnumIter code gen so that we produce `::core` to
+  avoid issues with shadowing modules.
+
 ## 0.25.1 (strum_macros)
 
 * [#276](https://github.com/Peternator7/strum/pull/276). Fixes [#275](https://github.com/Peternator7/strum/issues/275) and 
diff --git a/strum_macros/Cargo.toml b/strum_macros/Cargo.toml
index d294cb1..533e730 100644
--- a/strum_macros/Cargo.toml
+++ b/strum_macros/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "strum_macros"
-version = "0.25.1"
+version = "0.25.3"
 edition = "2018"
 authors = ["Peter Glotfelty <peter.glotfelty@microsoft.com>"]
 license = "MIT"
diff --git a/strum_macros/src/helpers/case_style.rs b/strum_macros/src/helpers/case_style.rs
index d6b2270..86a8583 100644
--- a/strum_macros/src/helpers/case_style.rs
+++ b/strum_macros/src/helpers/case_style.rs
@@ -158,3 +158,20 @@ mod tests {
         assert_eq!(MixedCase, f("mixed_case").unwrap());
     }
 }
+
+/// heck doesn't treat numbers as new words, but this function does.
+/// E.g. for input `Hello2You`, heck would output `hello2_you`, and snakify would output `hello_2_you`.
+pub fn snakify(s: &str) -> String {
+    let mut output: Vec<char> = s.to_string().to_snake_case().chars().collect();
+    let mut num_starts = vec![];
+    for (pos, c) in output.iter().enumerate() {
+        if c.is_digit(10) && pos != 0 && !output[pos - 1].is_digit(10) {
+            num_starts.push(pos);
+        }
+    }
+    // need to do in reverse, because after inserting, all chars after the point of insertion are off
+    for i in num_starts.into_iter().rev() {
+        output.insert(i, '_')
+    }
+    output.into_iter().collect()
+}
diff --git a/strum_macros/src/helpers/mod.rs b/strum_macros/src/helpers/mod.rs
index 11aebc8..142ea0b 100644
--- a/strum_macros/src/helpers/mod.rs
+++ b/strum_macros/src/helpers/mod.rs
@@ -1,4 +1,4 @@
-pub use self::case_style::CaseStyleHelpers;
+pub use self::case_style::{CaseStyleHelpers, snakify};
 pub use self::type_props::HasTypeProperties;
 pub use self::variant_props::HasStrumVariantProperties;
 
diff --git a/strum_macros/src/helpers/type_props.rs b/strum_macros/src/helpers/type_props.rs
index 0d49e04..17d84c9 100644
--- a/strum_macros/src/helpers/type_props.rs
+++ b/strum_macros/src/helpers/type_props.rs
@@ -21,6 +21,7 @@ pub struct StrumTypeProperties {
     pub discriminant_others: Vec<TokenStream>,
     pub discriminant_vis: Option<Visibility>,
     pub use_phf: bool,
+    pub enum_repr: Option<TokenStream>,
 }
 
 impl HasTypeProperties for DeriveInput {
@@ -103,6 +104,17 @@ impl HasTypeProperties for DeriveInput {
             }
         }
 
+        let attrs = &self.attrs;
+        for attr in attrs {
+            if let Ok(list) = attr.meta.require_list() {
+                if let Some(ident) = list.path.get_ident() {
+                    if ident == "repr" {
+                        output.enum_repr = Some(list.tokens.clone())
+                    }
+                }
+            }
+        }
+
         Ok(output)
     }
 }
diff --git a/strum_macros/src/lib.rs b/strum_macros/src/lib.rs
index a37ccdc..82db12a 100644
--- a/strum_macros/src/lib.rs
+++ b/strum_macros/src/lib.rs
@@ -409,6 +409,41 @@ pub fn enum_is(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
     toks.into()
 }
 
+/// Generated `try_as_*()` methods for all tuple-style variants.
+/// E.g. `Message.try_as_write()`.
+///
+/// These methods will only be generated for tuple-style variants, not for named or unit variants.
+///
+/// ```
+/// use strum_macros::EnumTryAs;
+///
+/// #[derive(EnumTryAs, Debug)]
+/// enum Message {
+///     Quit,
+///     Move { x: i32, y: i32 },
+///     Write(String),
+///     ChangeColor(i32, i32, i32),
+/// }
+///
+/// assert_eq!(
+///     Message::Write(String::from("Hello")).try_as_write(),
+///     Some(String::from("Hello"))
+/// );
+/// assert_eq!(
+///     Message::ChangeColor(1, 2, 3).try_as_change_color(),
+///     Some((1, 2, 3))
+/// );
+/// ```
+#[proc_macro_derive(EnumTryAs, attributes(strum))]
+pub fn enum_try_as(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let ast = syn::parse_macro_input!(input as DeriveInput);
+
+    let toks =
+        macros::enum_try_as::enum_try_as_inner(&ast).unwrap_or_else(|err| err.to_compile_error());
+    debug_print_generated(&ast, &toks);
+    toks.into()
+}
+
 /// Add a function to enum that allows accessing variants by its discriminant
 ///
 /// This macro adds a standalone function to obtain an enum variant by its discriminant. The macro adds
@@ -713,7 +748,7 @@ pub fn enum_properties(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
 /// of the generated enum. By default, the generated enum inherits the
 /// visibility of the parent enum it was generated from.
 ///
-/// ```nocompile
+/// ```
 /// use strum_macros::EnumDiscriminants;
 ///
 /// // You can set the visibility of the generated enum using the `#[strum_discriminants(vis(..))]` attribute:
diff --git a/strum_macros/src/macros/enum_discriminants.rs b/strum_macros/src/macros/enum_discriminants.rs
index 4e54a30..f7d6372 100644
--- a/strum_macros/src/macros/enum_discriminants.rs
+++ b/strum_macros/src/macros/enum_discriminants.rs
@@ -40,10 +40,16 @@ pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     // Pass through all other attributes
     let pass_though_attributes = type_properties.discriminant_others;
 
+    let repr = type_properties.enum_repr.map(|repr| quote!(#[repr(#repr)]));
+
     // Add the variants without fields, but exclude the `strum` meta item
     let mut discriminants = Vec::new();
     for variant in variants {
         let ident = &variant.ident;
+        let discriminant = variant
+            .discriminant
+            .as_ref()
+            .map(|(_, expr)| quote!( = #expr));
 
         // Don't copy across the "strum" meta attribute. Only passthrough the whitelisted
         // attributes and proxy `#[strum_discriminants(...)]` attributes
@@ -81,7 +87,7 @@ pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
             })
             .collect::<Result<Vec<_>, _>>()?;
 
-        discriminants.push(quote! { #(#attrs)* #ident });
+        discriminants.push(quote! { #(#attrs)* #ident #discriminant});
     }
 
     // Ideally:
@@ -153,6 +159,7 @@ pub fn enum_discriminants_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     Ok(quote! {
         /// Auto-generated discriminant enum variants
         #derives
+        #repr
         #(#[ #pass_though_attributes ])*
         #discriminants_vis enum #discriminants_name {
             #(#discriminants),*
diff --git a/strum_macros/src/macros/enum_is.rs b/strum_macros/src/macros/enum_is.rs
index bde3851..ecada45 100644
--- a/strum_macros/src/macros/enum_is.rs
+++ b/strum_macros/src/macros/enum_is.rs
@@ -1,5 +1,4 @@
-use crate::helpers::{non_enum_error, HasStrumVariantProperties};
-use heck::ToSnakeCase;
+use crate::helpers::{non_enum_error, snakify, HasStrumVariantProperties};
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
 use syn::{Data, DeriveInput};
@@ -9,9 +8,9 @@ pub fn enum_is_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         Data::Enum(v) => &v.variants,
         _ => return Err(non_enum_error()),
     };
+    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
 
     let enum_name = &ast.ident;
-
     let variants: Vec<_> = variants
         .iter()
         .filter_map(|variant| {
@@ -21,10 +20,11 @@ pub fn enum_is_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
 
             let variant_name = &variant.ident;
             let fn_name = format_ident!("is_{}", snakify(&variant_name.to_string()));
-
+            let doc_comment = format!("Returns [true] if the enum is [{}::{}] otherwise [false]", enum_name, variant_name);
             Some(quote! {
                 #[must_use]
                 #[inline]
+                #[doc = #doc_comment]
                 pub const fn #fn_name(&self) -> bool {
                     match self {
                         &#enum_name::#variant_name { .. } => true,
@@ -36,26 +36,9 @@ pub fn enum_is_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         .collect();
 
     Ok(quote! {
-        impl #enum_name {
+        impl #impl_generics #enum_name  #ty_generics #where_clause {
             #(#variants)*
         }
     }
     .into())
 }
-
-/// heck doesn't treat numbers as new words, but this function does.
-/// E.g. for input `Hello2You`, heck would output `hello2_you`, and snakify would output `hello_2_you`.
-fn snakify(s: &str) -> String {
-    let mut output: Vec<char> = s.to_string().to_snake_case().chars().collect();
-    let mut num_starts = vec![];
-    for (pos, c) in output.iter().enumerate() {
-        if c.is_digit(10) && pos != 0 && !output[pos - 1].is_digit(10) {
-            num_starts.push(pos);
-        }
-    }
-    // need to do in reverse, because after inserting, all chars after the point of insertion are off
-    for i in num_starts.into_iter().rev() {
-        output.insert(i, '_')
-    }
-    output.into_iter().collect()
-}
diff --git a/strum_macros/src/macros/enum_iter.rs b/strum_macros/src/macros/enum_iter.rs
index ce8237f..0e700aa 100644
--- a/strum_macros/src/macros/enum_iter.rs
+++ b/strum_macros/src/macros/enum_iter.rs
@@ -91,7 +91,7 @@ pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         }
 
         impl #impl_generics #iter_name #ty_generics #where_clause {
-            fn get(&self, idx: usize) -> Option<#name #ty_generics> {
+            fn get(&self, idx: usize) -> ::core::option::Option<#name #ty_generics> {
                 match idx {
                     #(#arms),*
                 }
@@ -112,16 +112,16 @@ pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
             type Item = #name #ty_generics;
 
-            fn next(&mut self) -> Option<<Self as Iterator>::Item> {
+            fn next(&mut self) -> ::core::option::Option<<Self as Iterator>::Item> {
                 self.nth(0)
             }
 
-            fn size_hint(&self) -> (usize, Option<usize>) {
+            fn size_hint(&self) -> (usize, ::core::option::Option<usize>) {
                 let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                 (t, Some(t))
             }
 
-            fn nth(&mut self, n: usize) -> Option<<Self as Iterator>::Item> {
+            fn nth(&mut self, n: usize) -> ::core::option::Option<<Self as Iterator>::Item> {
                 let idx = self.idx + n + 1;
                 if idx + self.back_idx > #variant_count {
                     // We went past the end of the iterator. Freeze idx at #variant_count
@@ -143,7 +143,7 @@ pub fn enum_iter_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         }
 
         impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
-            fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
+            fn next_back(&mut self) -> ::core::option::Option<<Self as Iterator>::Item> {
                 let back_idx = self.back_idx + 1;
 
                 if self.idx + back_idx > #variant_count {
diff --git a/strum_macros/src/macros/enum_properties.rs b/strum_macros/src/macros/enum_properties.rs
index 0fe389e..2583096 100644
--- a/strum_macros/src/macros/enum_properties.rs
+++ b/strum_macros/src/macros/enum_properties.rs
@@ -19,8 +19,6 @@ pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         let ident = &variant.ident;
         let variant_properties = variant.get_variant_properties()?;
         let mut string_arms = Vec::new();
-        let mut bool_arms = Vec::new();
-        let mut num_arms = Vec::new();
         // But you can disable the messages.
         if variant_properties.disabled.is_some() {
             continue;
@@ -37,8 +35,6 @@ pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         }
 
         string_arms.push(quote! { _ => ::core::option::Option::None });
-        bool_arms.push(quote! { _ => ::core::option::Option::None });
-        num_arms.push(quote! { _ => ::core::option::Option::None });
 
         arms.push(quote! {
             &#name::#ident #params => {
diff --git a/strum_macros/src/macros/enum_try_as.rs b/strum_macros/src/macros/enum_try_as.rs
new file mode 100644
index 0000000..088a1f1
--- /dev/null
+++ b/strum_macros/src/macros/enum_try_as.rs
@@ -0,0 +1,80 @@
+use crate::helpers::{non_enum_error, snakify, HasStrumVariantProperties};
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, ToTokens};
+use syn::{Data, DeriveInput};
+
+pub fn enum_try_as_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
+    let variants = match &ast.data {
+        Data::Enum(v) => &v.variants,
+        _ => return Err(non_enum_error()),
+    };
+
+    let enum_name = &ast.ident;
+
+    let variants: Vec<_> = variants
+        .iter()
+        .filter_map(|variant| {
+            if variant.get_variant_properties().ok()?.disabled.is_some() {
+                return None;
+            }
+
+            match &variant.fields {
+                syn::Fields::Unnamed(values) => {
+                    let variant_name = &variant.ident;
+                    let types: Vec<_> = values.unnamed.iter().map(|field| {
+                        field.to_token_stream()
+                    }).collect();
+                    let field_names: Vec<_> = values.unnamed.iter().enumerate().map(|(i, _)| {
+                        let name = "x".repeat(i + 1);
+                        let name = format_ident!("{}", name);
+                        quote! {#name}
+                    }).collect();
+
+                    let move_fn_name = format_ident!("try_as_{}", snakify(&variant_name.to_string()));
+                    let ref_fn_name = format_ident!("try_as_{}_ref", snakify(&variant_name.to_string()));
+                    let mut_fn_name = format_ident!("try_as_{}_mut", snakify(&variant_name.to_string()));
+
+                    Some(quote! {
+                        #[must_use]
+                        #[inline]
+                        pub fn #move_fn_name(self) -> ::core::option::Option<(#(#types),*)> {
+                            match self {
+                                #enum_name::#variant_name (#(#field_names),*) => Some((#(#field_names),*)),
+                                _ => None
+                            }
+                        }
+
+                        #[must_use]
+                        #[inline]
+                        pub const fn #ref_fn_name(&self) -> ::core::option::Option<(#(&#types),*)> {
+                            match self {
+                                #enum_name::#variant_name (#(#field_names),*) => Some((#(#field_names),*)),
+                                _ => None
+                            }
+                        }
+
+                        #[must_use]
+                        #[inline]
+                        pub fn #mut_fn_name(&mut self) -> ::core::option::Option<(#(&mut #types),*)> {
+                            match self {
+                                #enum_name::#variant_name (#(#field_names),*) => Some((#(#field_names),*)),
+                                _ => None
+                            }
+                        }
+                    })
+                },
+                _ => {
+                    return None;
+                }
+            }
+
+        })
+        .collect();
+
+    Ok(quote! {
+        impl #enum_name {
+            #(#variants)*
+        }
+    }
+    .into())
+}
diff --git a/strum_macros/src/macros/from_repr.rs b/strum_macros/src/macros/from_repr.rs
index 92fd7ad..a70c6f8 100644
--- a/strum_macros/src/macros/from_repr.rs
+++ b/strum_macros/src/macros/from_repr.rs
@@ -1,62 +1,32 @@
 use heck::ToShoutySnakeCase;
 use proc_macro2::{Span, TokenStream};
-use quote::{format_ident, quote, ToTokens};
-use syn::{Data, DeriveInput, Fields, PathArguments, Type, TypeParen};
+use quote::{format_ident, quote};
+use syn::{Data, DeriveInput, Fields, Type};
 
-use crate::helpers::{non_enum_error, HasStrumVariantProperties};
+use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
 
 pub fn from_repr_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     let name = &ast.ident;
     let gen = &ast.generics;
     let (impl_generics, ty_generics, where_clause) = gen.split_for_impl();
     let vis = &ast.vis;
-    let attrs = &ast.attrs;
 
     let mut discriminant_type: Type = syn::parse("usize".parse().unwrap()).unwrap();
-    for attr in attrs {
-        let path = attr.path();
-
-        let mut ts = if let Ok(ts) = attr
-            .meta
-            .require_list()
-            .map(|metas| metas.to_token_stream().into_iter())
-        {
-            ts
-        } else {
-            continue;
-        };
-        // Discard the path
-        let _ = ts.next();
-        let tokens: TokenStream = ts.collect();
-
-        if path.leading_colon.is_some() {
-            continue;
-        }
-        if path.segments.len() != 1 {
-            continue;
-        }
-        let segment = path.segments.first().unwrap();
-        if segment.ident != "repr" {
-            continue;
-        }
-        if segment.arguments != PathArguments::None {
-            continue;
-        }
-        let typ_paren = match syn::parse2::<Type>(tokens.clone()) {
-            Ok(Type::Paren(TypeParen { elem, .. })) => *elem,
-            _ => continue,
-        };
-        let inner_path = match &typ_paren {
-            Type::Path(t) => t,
-            _ => continue,
-        };
-        if let Some(seg) = inner_path.path.segments.last() {
-            for t in &[
-                "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize",
-            ] {
-                if seg.ident == t {
-                    discriminant_type = typ_paren;
-                    break;
+    if let Some(type_path) = ast
+        .get_type_properties()
+        .ok()
+        .and_then(|tp| tp.enum_repr)
+        .and_then(|repr_ts| syn::parse2::<Type>(repr_ts).ok())
+    {
+        if let Type::Path(path) = type_path.clone() {
+            if let Some(seg) = path.path.segments.last() {
+                for t in &[
+                    "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize",
+                ] {
+                    if seg.ident == t {
+                        discriminant_type = type_path;
+                        break;
+                    }
                 }
             }
         }
diff --git a/strum_macros/src/macros/mod.rs b/strum_macros/src/macros/mod.rs
index a44be08..8df8cd6 100644
--- a/strum_macros/src/macros/mod.rs
+++ b/strum_macros/src/macros/mod.rs
@@ -4,6 +4,7 @@ pub mod enum_is;
 pub mod enum_iter;
 pub mod enum_messages;
 pub mod enum_properties;
+pub mod enum_try_as;
 pub mod enum_variant_names;
 pub mod from_repr;
 
diff --git a/strum_macros/src/macros/strings/display.rs b/strum_macros/src/macros/strings/display.rs
index fcc5936..77f8afa 100644
--- a/strum_macros/src/macros/strings/display.rs
+++ b/strum_macros/src/macros/strings/display.rs
@@ -35,7 +35,7 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
         if variant_properties.to_string.is_none() && variant_properties.default.is_some() {
             match &variant.fields {
                 Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
-                    arms.push(quote! { #name::#ident(ref s) => f.pad(s) });
+                    arms.push(quote! { #name::#ident(ref s) => s.fmt(f) });
                 }
                 _ => {
                     return Err(syn::Error::new_spanned(
@@ -45,7 +45,7 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
                 }
             }
         } else {
-            arms.push(quote! { #name::#ident #params => f.pad(#output) });
+            arms.push(quote! { #name::#ident #params => (#output).fmt(f) } );
         }
     }
 


Test patch:
diff --git a/strum_tests/src/lib.rs b/strum_tests/src/lib.rs
index 3addd0d..eb3f65d 100644
--- a/strum_tests/src/lib.rs
+++ b/strum_tests/src/lib.rs
@@ -1,6 +1,7 @@
 use strum::{Display, EnumCount, EnumDiscriminants, EnumString};
+use strum_macros::EnumIs;
 
-#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants)]
+#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants, EnumIs)]
 pub enum Color {
     /// Docs on red
     #[strum(to_string = "RedRed")]
diff --git a/strum_tests/src/main.rs b/strum_tests/src/main.rs
index 4d048a6..97e348a 100644
--- a/strum_tests/src/main.rs
+++ b/strum_tests/src/main.rs
@@ -1,7 +1,8 @@
 use strum::{Display, EnumCount, EnumDiscriminants, EnumString};
+use strum_macros::EnumIs;
 
 #[allow(dead_code)]
-#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants)]
+#[derive(Debug, Eq, PartialEq, EnumString, Display, EnumCount, EnumDiscriminants, EnumIs)]
 enum Color {
     /// Random Docs
     #[strum(to_string = "RedRed")]
diff --git a/strum_tests/tests/display.rs b/strum_tests/tests/display.rs
index 4cec148..77ea25c 100644
--- a/strum_tests/tests/display.rs
+++ b/strum_tests/tests/display.rs
@@ -1,8 +1,8 @@
-use strum::{Display, EnumString};
+use strum::EnumString;
 
 mod core {} // ensure macros call `::core`
 
-#[derive(Debug, Eq, PartialEq, EnumString, Display)]
+#[derive(Debug, Eq, PartialEq, EnumString, strum::Display)]
 enum Color {
     #[strum(to_string = "RedRed")]
     Red,
@@ -49,12 +49,12 @@ fn to_red_string() {
 #[test]
 fn to_green_string() {
     assert_eq!(
-        String::from("lime"),
-        format!("{}", Color::Green("lime".into()))
+        String::from("  lime"),
+        format!("{:>6}", Color::Green("lime".into()))
     );
 }
 
-#[derive(Debug, Eq, PartialEq, EnumString, Display)]
+#[derive(Debug, Eq, PartialEq, EnumString, strum::Display)]
 enum ColorWithDefaultAndToString {
     #[strum(default, to_string = "GreenGreen")]
     Green(String),
@@ -68,7 +68,7 @@ fn to_green_with_default_and_to_string() {
     );
 }
 
-#[derive(Display, Debug, Eq, PartialEq)]
+#[derive(strum::Display, Debug, Eq, PartialEq)]
 #[strum(serialize_all = "snake_case")]
 enum Brightness {
     DarkBlack,
@@ -94,3 +94,18 @@ fn brightness_to_string() {
         Brightness::BrightWhite.to_string().as_ref()
     );
 }
+
+#[derive(strum::Display, Debug, Eq, PartialEq)]
+#[strum(serialize_all = "snake_case")]
+enum NonStringDefault {
+    #[strum(default)]
+    Number(usize),
+}
+
+#[test]
+fn non_string_default_to_string() {
+    assert_eq!(
+        String::from("0014"),
+        format!("{:04}", NonStringDefault::Number(14))
+    );
+}
diff --git a/strum_tests/tests/enum_discriminants.rs b/strum_tests/tests/enum_discriminants.rs
index eb29e6d..d6e4668 100644
--- a/strum_tests/tests/enum_discriminants.rs
+++ b/strum_tests/tests/enum_discriminants.rs
@@ -1,6 +1,9 @@
-use enum_variant_type::EnumVariantType;
-use strum::{Display, EnumDiscriminants, EnumIter, EnumMessage, EnumString, IntoEnumIterator};
+use std::mem::{align_of, size_of};
 
+use enum_variant_type::EnumVariantType;
+use strum::{
+    Display, EnumDiscriminants, EnumIter, EnumMessage, EnumString, FromRepr, IntoEnumIterator,
+};
 
 mod core {} // ensure macros call `::core`
 
@@ -305,3 +308,58 @@ fn crate_module_path_test() {
 
     assert_eq!(expected, discriminants);
 }
+
+#[allow(dead_code)]
+#[derive(EnumDiscriminants)]
+#[repr(u16)]
+enum WithReprUInt {
+    Variant0,
+    Variant1,
+}
+
+#[test]
+fn with_repr_uint() {
+    // These tests would not be proof of proper functioning on a 16 bit system
+    assert_eq!(size_of::<u16>(), size_of::<WithReprUIntDiscriminants>());
+    assert_eq!(
+        size_of::<WithReprUInt>(),
+        size_of::<WithReprUIntDiscriminants>()
+    )
+}
+
+#[allow(dead_code)]
+#[derive(EnumDiscriminants)]
+#[repr(align(16), u8)]
+enum WithReprAlign {
+    Variant0,
+    Variant1,
+}
+
+#[test]
+fn with_repr_align() {
+    assert_eq!(
+        align_of::<WithReprAlign>(),
+        align_of::<WithReprAlignDiscriminants>()
+    );
+    assert_eq!(16, align_of::<WithReprAlignDiscriminants>());
+}
+
+#[allow(dead_code)]
+#[derive(EnumDiscriminants)]
+#[strum_discriminants(derive(FromRepr))]
+enum WithExplicitDicriminantValue {
+    Variant0 = 42 + 100,
+    Variant1 = 11,
+}
+
+#[test]
+fn with_explicit_discriminant_value() {
+    assert_eq!(
+        WithExplicitDicriminantValueDiscriminants::from_repr(11),
+        Some(WithExplicitDicriminantValueDiscriminants::Variant1)
+    );
+    assert_eq!(
+        142,
+        WithExplicitDicriminantValueDiscriminants::Variant0 as u8
+    );
+}
diff --git a/strum_tests/tests/enum_is.rs b/strum_tests/tests/enum_is.rs
index 789881c..4e997fe 100644
--- a/strum_tests/tests/enum_is.rs
+++ b/strum_tests/tests/enum_is.rs
@@ -1,7 +1,12 @@
+use std::borrow::Cow;
 use strum::EnumIs;
 
 mod core {} // ensure macros call `::core`
-
+#[derive(EnumIs)]
+enum LifeTimeTest<'a>{
+    One(Cow<'a, str>),
+    Two(&'a str)
+}
 #[derive(EnumIs)]
 enum Foo {
     Unit,
@@ -16,7 +21,15 @@ enum Foo {
     #[allow(dead_code)]
     Disabled,
 }
-
+#[test]
+fn generics_test(){
+    let foo = LifeTimeTest::One(Cow::Borrowed("Hello"));
+    assert!(foo.is_one());
+    let foo = LifeTimeTest::Two("Hello");
+    assert!(foo.is_two());
+    let foo = LifeTimeTest::One(Cow::Owned("Hello".to_string()));
+    assert!(foo.is_one());
+}
 #[test]
 fn simple_test() {
     assert!(Foo::Unit.is_unit());
diff --git a/strum_tests/tests/enum_iter.rs b/strum_tests/tests/enum_iter.rs
index 313ed5c..ce6ecb2 100644
--- a/strum_tests/tests/enum_iter.rs
+++ b/strum_tests/tests/enum_iter.rs
@@ -211,3 +211,16 @@ fn crate_module_path_test() {
 
     assert_eq!(expected, results);
 }
+
+#[test]
+fn enum_iter_option() {
+    #[derive(Debug, Eq, PartialEq, EnumIter)]
+    enum Option {
+        BluePill,
+        RedPill,
+    }
+    let results = Option::iter().collect::<Vec<_>>();
+    let expected = vec![Option::BluePill, Option::RedPill];
+
+    assert_eq!(expected, results);
+}
diff --git a/strum_tests/tests/enum_try_as.rs b/strum_tests/tests/enum_try_as.rs
new file mode 100644
index 0000000..aa54205
--- /dev/null
+++ b/strum_tests/tests/enum_try_as.rs
@@ -0,0 +1,48 @@
+use strum::EnumTryAs;
+
+#[derive(EnumTryAs)]
+enum Foo {
+    Unnamed0(),
+    Unnamed1(u128),
+    Unnamed2(bool, String),
+    #[strum(disabled)]
+    #[allow(dead_code)]
+    Disabled(u32),
+    #[allow(dead_code)]
+    Unit,
+    #[allow(dead_code)]
+    Named { _a: u32, _b: String },
+}
+
+#[test]
+fn unnamed_0() {
+    let foo = Foo::Unnamed0();
+    assert_eq!(Some(()), foo.try_as_unnamed_0());
+}
+
+#[test]
+fn unnamed_1() {
+    let foo = Foo::Unnamed1(128);
+    assert_eq!(Some(&128), foo.try_as_unnamed_1_ref());
+}
+
+#[test]
+fn unnamed_2() {
+    let foo = Foo::Unnamed2(true, String::from("Hay"));
+    assert_eq!(Some((true, String::from("Hay"))), foo.try_as_unnamed_2());
+}
+
+#[test]
+fn can_mutate() {
+    let mut foo = Foo::Unnamed1(128);
+    if let Some(value) = foo.try_as_unnamed_1_mut() {
+        *value = 44_u128;
+    }
+    assert_eq!(foo.try_as_unnamed_1(), Some(44));
+}
+
+#[test]
+fn doesnt_match_other_variations() {
+    let foo = Foo::Unnamed1(66);
+    assert_eq!(None, foo.try_as_unnamed_0());
+}