diff --git a/Cargo.lock b/Cargo.lock index bd7e639..8648df5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,8 @@ name = "any_generics" version = "0.1.0" dependencies = [ "nutype", + "serde", + "serde_json", ] [[package]] @@ -113,7 +115,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.66", ] [[package]] @@ -205,7 +207,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.66", ] [[package]] @@ -252,7 +254,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.39", + "syn 2.0.66", "urlencoding", ] @@ -270,18 +272,18 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.29" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -381,9 +383,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.192" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -399,13 +401,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.66", ] [[package]] @@ -421,9 +423,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -468,9 +470,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", diff --git a/examples/any_generics/Cargo.toml b/examples/any_generics/Cargo.toml index 10a487c..fa5f947 100644 --- a/examples/any_generics/Cargo.toml +++ b/examples/any_generics/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nutype = { path = "../../nutype" } +nutype = { path = "../../nutype", features = ["serde"] } +serde = "1.0.203" +serde_json = "1.0.117" diff --git a/examples/any_generics/src/main.rs b/examples/any_generics/src/main.rs index 8ef2774..698f053 100644 --- a/examples/any_generics/src/main.rs +++ b/examples/any_generics/src/main.rs @@ -21,15 +21,15 @@ struct NotEmpty(Vec); Deref, Borrow, AsRef, + Serialize, + Deserialize, // TODO // FromStr, // TryFrom, // Default, - // Serialize, - // Deserialize, // Arbitrary, ))] -struct Clarabelle<'b>(Cow<'b, str>); +struct Clarabelle<'a>(Cow<'a, str>); fn main() { { @@ -44,5 +44,11 @@ fn main() { { let muu = Clarabelle::new(Cow::Borrowed("Muu")); assert_eq!(muu.to_string(), "Muu"); + // serialize muu with serde_json + let json = serde_json::to_string(&muu).unwrap(); + assert_eq!(json, "\"Muu\""); + // deserialize muu with serde_json + let same_muu: Clarabelle = serde_json::from_str(&json).unwrap(); + assert_eq!(muu, same_muu); } } diff --git a/nutype_macros/src/any/gen/traits/mod.rs b/nutype_macros/src/any/gen/traits/mod.rs index 8e57da3..7d98909 100644 --- a/nutype_macros/src/any/gen/traits/mod.rs +++ b/nutype_macros/src/any/gen/traits/mod.rs @@ -177,10 +177,10 @@ fn gen_implemented_traits( } }, AnyIrregularTrait::SerdeSerialize => Ok( - gen_impl_trait_serde_serialize(type_name) + gen_impl_trait_serde_serialize(type_name, generics) ), AnyIrregularTrait::SerdeDeserialize => Ok( - gen_impl_trait_serde_deserialize(type_name, inner_type, maybe_error_type_name.as_ref()) + gen_impl_trait_serde_deserialize(type_name, generics, inner_type, maybe_error_type_name.as_ref()) ), AnyIrregularTrait::ArbitraryArbitrary => arbitrary::gen_impl_trait_arbitrary(type_name, inner_type, guard), }) diff --git a/nutype_macros/src/common/gen/traits.rs b/nutype_macros/src/common/gen/traits.rs index 52acbab..3756cc7 100644 --- a/nutype_macros/src/common/gen/traits.rs +++ b/nutype_macros/src/common/gen/traits.rs @@ -238,10 +238,10 @@ pub fn gen_impl_trait_from_str( } } -pub fn gen_impl_trait_serde_serialize(type_name: &TypeName) -> TokenStream { +pub fn gen_impl_trait_serde_serialize(type_name: &TypeName, generics: &Generics) -> TokenStream { let type_name_str = type_name.to_string(); quote! { - impl ::serde::Serialize for #type_name { + impl #generics ::serde::Serialize for #type_name #generics { fn serialize(&self, serializer: S) -> ::core::result::Result where S: ::serde::Serializer @@ -254,6 +254,7 @@ pub fn gen_impl_trait_serde_serialize(type_name: &TypeName) -> TokenStream { pub fn gen_impl_trait_serde_deserialize( type_name: &TypeName, + type_generics: &Generics, inner_type: impl Into, maybe_error_type_name: Option<&ErrorTypeName>, ) -> TokenStream { @@ -276,16 +277,23 @@ pub fn gen_impl_trait_serde_deserialize( let expecting_str = format!("tuple struct {type_name}"); let type_name_str = type_name.to_string(); + // type generics + 'de lifetime for Deserialize + let all_generics = { + let mut all_generics = type_generics.clone(); + all_generics.params.push(syn::parse_quote!('de)); + all_generics + }; + quote! { - impl<'de> ::serde::Deserialize<'de> for #type_name { + impl #all_generics ::serde::Deserialize<'de> for #type_name #type_generics { fn deserialize>(deserializer: D) -> Result { - struct __Visitor<'de> { - marker: ::std::marker::PhantomData<#type_name>, + struct __Visitor #all_generics { + marker: ::std::marker::PhantomData<#type_name #type_generics>, lifetime: ::std::marker::PhantomData<&'de ()>, } - impl<'de> ::serde::de::Visitor<'de> for __Visitor<'de> { - type Value = #type_name; + impl #all_generics ::serde::de::Visitor<'de> for __Visitor #all_generics { + type Value = #type_name #type_generics; fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(formatter, #expecting_str) diff --git a/nutype_macros/src/float/gen/traits/mod.rs b/nutype_macros/src/float/gen/traits/mod.rs index 548315d..4d21d77 100644 --- a/nutype_macros/src/float/gen/traits/mod.rs +++ b/nutype_macros/src/float/gen/traits/mod.rs @@ -192,9 +192,10 @@ fn gen_implemented_traits( Err(syn::Error::new(span, msg)) } }, - FloatIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name)), + FloatIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name, generics)), FloatIrregularTrait::SerdeDeserialize => Ok(gen_impl_trait_serde_deserialize( type_name, + generics, 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 52106a2..9dd265a 100644 --- a/nutype_macros/src/integer/gen/traits/mod.rs +++ b/nutype_macros/src/integer/gen/traits/mod.rs @@ -214,9 +214,10 @@ fn gen_implemented_traits( } } } - IntegerIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name)), + IntegerIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name, generics)), IntegerIrregularTrait::SerdeDeserialize => Ok(gen_impl_trait_serde_deserialize( type_name, + generics, 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 5d9737c..c262d45 100644 --- a/nutype_macros/src/string/gen/traits/mod.rs +++ b/nutype_macros/src/string/gen/traits/mod.rs @@ -210,9 +210,10 @@ fn gen_implemented_traits( Err(syn::Error::new(span, msg)) } }, - StringIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name)), + StringIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name, generics)), StringIrregularTrait::SerdeDeserialize => Ok(gen_impl_trait_serde_deserialize( type_name, + generics, inner_type, maybe_error_type_name.as_ref(), )), diff --git a/test_suite/tests/any.rs b/test_suite/tests/any.rs index 9c1fb60..7eb1308 100644 --- a/test_suite/tests/any.rs +++ b/test_suite/tests/any.rs @@ -329,6 +329,53 @@ mod traits { assert_eq!(deserialized, place); } } + + mod with_generics { + use super::*; + + // TODO: Uncomment when https://github.com/greyblake/nutype/issues/142 is fixed + // #[test] + // fn test_generic_with_serde() { + // #[nutype( + // derive(Debug, Serialize, Deserialize), + // validate(predicate = |v| v.is_empty()) + // )] + // struct EmptyVec(Vec); + + // { + // let vec = EmptyVec::new(vec![]); + // let json = serde_json::to_string(&vec).unwrap(); + // assert_eq!(json, "[]"); + + // let same_vec: EmptyVec = serde_json::from_str(&json).unwrap(); + // assert_eq!(vec, same_vec); + // } + + // { + // let vec = EmptyVec::new(vec![1, 2, 3]); + // let err = serde_json::to_string(&vec).unwrap_err(); + // assert_eq!( + // err.to_string(), + // "EmptyVec failed the predicate test. Expected valid EmptyVec" + // ); + // } + // } + + #[test] + fn serialize_and_deserialize_cow() { + #[nutype( + validate(predicate = |s| s.len() >= 3), + derive(Debug, Serialize, Deserialize, PartialEq) + )] + struct Clarabelle<'a>(Cow<'a, str>); + + let muu = Clarabelle::new(Cow::Borrowed("Muu")).unwrap(); + let json = serde_json::to_string(&muu).unwrap(); + assert_eq!(json, "\"Muu\""); + let same_muu: Clarabelle = serde_json::from_str(&json).unwrap(); + assert_eq!(muu, same_muu); + } + } } }