Repository: greyblake/nutype (Rust)

Issue:
Derive AsRef for generic newtype
The following types should compile and work as expected:

```rs
use nutype::nutype;
use std::borrow::Cow;

#[nutype(derive(AsRef))]
struct NotEmpty<T>(Vec<T>);

#[nutype(derive(AsRef))]
struct Clarabelle<'a>(Cow<'a, str>);
```

Make sure to have a proper test coverage


Discussion:

Patch:
diff --git a/examples/any_generics/src/main.rs b/examples/any_generics/src/main.rs
index 250a7f3..8ef2774 100644
--- a/examples/any_generics/src/main.rs
+++ b/examples/any_generics/src/main.rs
@@ -20,8 +20,8 @@ struct NotEmpty<T>(Vec<T>);
     From,
     Deref,
     Borrow,
+    AsRef,
     // TODO
-    // AsRef,
     // FromStr,
     // TryFrom,
     // Default,
diff --git a/nutype_macros/src/any/gen/traits/mod.rs b/nutype_macros/src/any/gen/traits/mod.rs
index 0c80950..8e57da3 100644
--- a/nutype_macros/src/any/gen/traits/mod.rs
+++ b/nutype_macros/src/any/gen/traits/mod.rs
@@ -153,7 +153,7 @@ fn gen_implemented_traits(
     impl_traits
         .iter()
         .map(|t| match t {
-            AnyIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, inner_type)),
+            AnyIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, generics, inner_type)),
             AnyIrregularTrait::From => Ok(gen_impl_trait_from(type_name, generics, inner_type)),
             AnyIrregularTrait::Into => Ok(gen_impl_trait_into(type_name, generics, inner_type.clone())),
             AnyIrregularTrait::Display => Ok(gen_impl_trait_display(type_name, generics)),
diff --git a/nutype_macros/src/common/gen/traits.rs b/nutype_macros/src/common/gen/traits.rs
index 2ece351..52acbab 100644
--- a/nutype_macros/src/common/gen/traits.rs
+++ b/nutype_macros/src/common/gen/traits.rs
@@ -73,9 +73,13 @@ pub fn gen_impl_trait_into(
     }
 }
 
-pub fn gen_impl_trait_as_ref(type_name: &TypeName, inner_type: impl ToTokens) -> TokenStream {
+pub fn gen_impl_trait_as_ref(
+    type_name: &TypeName,
+    generics: &Generics,
+    inner_type: impl ToTokens,
+) -> TokenStream {
     quote! {
-        impl ::core::convert::AsRef<#inner_type> for #type_name {
+        impl #generics ::core::convert::AsRef<#inner_type> for #type_name #generics {
             #[inline]
             fn as_ref(&self) -> &#inner_type {
                 &self.0
diff --git a/nutype_macros/src/float/gen/traits/mod.rs b/nutype_macros/src/float/gen/traits/mod.rs
index 20bca68..548315d 100644
--- a/nutype_macros/src/float/gen/traits/mod.rs
+++ b/nutype_macros/src/float/gen/traits/mod.rs
@@ -169,7 +169,7 @@ fn gen_implemented_traits<T: ToTokens>(
     impl_traits
         .iter()
         .map(|t| match t {
-            FloatIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, inner_type)),
+            FloatIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, generics, inner_type)),
             FloatIrregularTrait::Deref => Ok(gen_impl_trait_deref(type_name, generics, inner_type)),
             FloatIrregularTrait::FromStr => {
                 Ok(gen_impl_trait_from_str(type_name, inner_type, maybe_error_type_name.as_ref()))
diff --git a/nutype_macros/src/integer/gen/traits/mod.rs b/nutype_macros/src/integer/gen/traits/mod.rs
index c7fe088..52106a2 100644
--- a/nutype_macros/src/integer/gen/traits/mod.rs
+++ b/nutype_macros/src/integer/gen/traits/mod.rs
@@ -189,7 +189,7 @@ fn gen_implemented_traits<T: ToTokens>(
     impl_traits
         .iter()
         .map(|t| match t {
-            IntegerIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, inner_type)),
+            IntegerIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, generics, inner_type)),
             IntegerIrregularTrait::Deref => Ok(gen_impl_trait_deref(type_name, generics, inner_type)),
             IntegerIrregularTrait::FromStr => {
                 Ok(gen_impl_trait_from_str(type_name, inner_type, maybe_error_type_name.as_ref()))
diff --git a/nutype_macros/src/string/gen/traits/mod.rs b/nutype_macros/src/string/gen/traits/mod.rs
index 4896945..5d9737c 100644
--- a/nutype_macros/src/string/gen/traits/mod.rs
+++ b/nutype_macros/src/string/gen/traits/mod.rs
@@ -183,7 +183,7 @@ fn gen_implemented_traits(
     impl_traits
         .iter()
         .map(|t| match t {
-            StringIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, quote!(str))),
+            StringIrregularTrait::AsRef => Ok(gen_impl_trait_as_ref(type_name, generics, quote!(str))),
             StringIrregularTrait::Deref => Ok(gen_impl_trait_deref(type_name, generics, quote!(String))),
             StringIrregularTrait::FromStr => {
                 Ok(gen_impl_from_str(type_name, maybe_error_type_name.as_ref()))


Test patch:
diff --git a/test_suite/tests/any.rs b/test_suite/tests/any.rs
index a30555d..9c1fb60 100644
--- a/test_suite/tests/any.rs
+++ b/test_suite/tests/any.rs
@@ -1,5 +1,6 @@
 use nutype::nutype;
 use std::borrow::Cow;
+use std::collections::HashMap;
 use test_suite::test_helpers::traits::*;
 
 // Inner custom type, which is unknown to nutype
@@ -488,7 +489,7 @@ mod with_generics {
     fn test_generic_with_lifetime_cow() {
         #[nutype(
             validate(predicate = |s| s.len() >= 3),
-            derive(Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Into, Deref, Borrow, TryFrom)
+            derive(Debug, Display, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Into, Deref, Borrow, TryFrom, AsRef)
         )]
         struct Clarabelle<'a>(Cow<'a, str>);
 
@@ -500,4 +501,31 @@ mod with_generics {
             assert_eq!(muu.to_string(), "Muu");
         }
     }
+
+    #[test]
+    fn test_derive_as_ref_with_generic() {
+        #[nutype(derive(AsRef))]
+        struct SquareMap<K, V>(HashMap<K, V>);
+
+        let mut inner_map = HashMap::new();
+        inner_map.insert(4, 16);
+        inner_map.insert(5, 25);
+        let squares = SquareMap::new(inner_map.clone());
+        assert_eq!(squares.as_ref(), &inner_map);
+    }
+
+    #[test]
+    fn test_derive_as_ref_with_generic_and_validation() {
+        #[nutype(
+            validate(predicate = |map| map.len() > 1),
+            derive(AsRef)
+        )]
+        struct NonEmptyMap<K, V>(HashMap<K, V>);
+
+        let mut inner_map = HashMap::new();
+        inner_map.insert(4, 16);
+        inner_map.insert(5, 25);
+        let squares = NonEmptyMap::new(inner_map.clone()).unwrap();
+        assert_eq!(squares.as_ref(), &inner_map);
+    }
 }