Skip to content

Commit 05adaa1

Browse files
authored
Merge pull request #144 from greyblake/generics-derive-serde
Make it possible to derive Serialize and Deserialize on Cow<a, str>
2 parents 67ecaa5 + 28f8820 commit 05adaa1

File tree

9 files changed

+100
-32
lines changed

9 files changed

+100
-32
lines changed

Cargo.lock

+18-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/any_generics/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
nutype = { path = "../../nutype" }
9+
nutype = { path = "../../nutype", features = ["serde"] }
10+
serde = "1.0.203"
11+
serde_json = "1.0.117"

examples/any_generics/src/main.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ struct NotEmpty<T>(Vec<T>);
2121
Deref,
2222
Borrow,
2323
AsRef,
24+
Serialize,
25+
Deserialize,
2426
// TODO
2527
// FromStr,
2628
// TryFrom,
2729
// Default,
28-
// Serialize,
29-
// Deserialize,
3030
// Arbitrary,
3131
))]
32-
struct Clarabelle<'b>(Cow<'b, str>);
32+
struct Clarabelle<'a>(Cow<'a, str>);
3333

3434
fn main() {
3535
{
@@ -44,5 +44,11 @@ fn main() {
4444
{
4545
let muu = Clarabelle::new(Cow::Borrowed("Muu"));
4646
assert_eq!(muu.to_string(), "Muu");
47+
// serialize muu with serde_json
48+
let json = serde_json::to_string(&muu).unwrap();
49+
assert_eq!(json, "\"Muu\"");
50+
// deserialize muu with serde_json
51+
let same_muu: Clarabelle = serde_json::from_str(&json).unwrap();
52+
assert_eq!(muu, same_muu);
4753
}
4854
}

nutype_macros/src/any/gen/traits/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ fn gen_implemented_traits(
177177
}
178178
},
179179
AnyIrregularTrait::SerdeSerialize => Ok(
180-
gen_impl_trait_serde_serialize(type_name)
180+
gen_impl_trait_serde_serialize(type_name, generics)
181181
),
182182
AnyIrregularTrait::SerdeDeserialize => Ok(
183-
gen_impl_trait_serde_deserialize(type_name, inner_type, maybe_error_type_name.as_ref())
183+
gen_impl_trait_serde_deserialize(type_name, generics, inner_type, maybe_error_type_name.as_ref())
184184
),
185185
AnyIrregularTrait::ArbitraryArbitrary => arbitrary::gen_impl_trait_arbitrary(type_name, inner_type, guard),
186186
})

nutype_macros/src/common/gen/traits.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,10 @@ pub fn gen_impl_trait_from_str(
238238
}
239239
}
240240

241-
pub fn gen_impl_trait_serde_serialize(type_name: &TypeName) -> TokenStream {
241+
pub fn gen_impl_trait_serde_serialize(type_name: &TypeName, generics: &Generics) -> TokenStream {
242242
let type_name_str = type_name.to_string();
243243
quote! {
244-
impl ::serde::Serialize for #type_name {
244+
impl #generics ::serde::Serialize for #type_name #generics {
245245
fn serialize<S>(&self, serializer: S) -> ::core::result::Result<S::Ok, S::Error>
246246
where
247247
S: ::serde::Serializer
@@ -254,6 +254,7 @@ pub fn gen_impl_trait_serde_serialize(type_name: &TypeName) -> TokenStream {
254254

255255
pub fn gen_impl_trait_serde_deserialize(
256256
type_name: &TypeName,
257+
type_generics: &Generics,
257258
inner_type: impl Into<InnerType>,
258259
maybe_error_type_name: Option<&ErrorTypeName>,
259260
) -> TokenStream {
@@ -276,16 +277,23 @@ pub fn gen_impl_trait_serde_deserialize(
276277
let expecting_str = format!("tuple struct {type_name}");
277278
let type_name_str = type_name.to_string();
278279

280+
// type generics + 'de lifetime for Deserialize
281+
let all_generics = {
282+
let mut all_generics = type_generics.clone();
283+
all_generics.params.push(syn::parse_quote!('de));
284+
all_generics
285+
};
286+
279287
quote! {
280-
impl<'de> ::serde::Deserialize<'de> for #type_name {
288+
impl #all_generics ::serde::Deserialize<'de> for #type_name #type_generics {
281289
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
282-
struct __Visitor<'de> {
283-
marker: ::std::marker::PhantomData<#type_name>,
290+
struct __Visitor #all_generics {
291+
marker: ::std::marker::PhantomData<#type_name #type_generics>,
284292
lifetime: ::std::marker::PhantomData<&'de ()>,
285293
}
286294

287-
impl<'de> ::serde::de::Visitor<'de> for __Visitor<'de> {
288-
type Value = #type_name;
295+
impl #all_generics ::serde::de::Visitor<'de> for __Visitor #all_generics {
296+
type Value = #type_name #type_generics;
289297

290298
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
291299
write!(formatter, #expecting_str)

nutype_macros/src/float/gen/traits/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,10 @@ fn gen_implemented_traits<T: ToTokens>(
192192
Err(syn::Error::new(span, msg))
193193
}
194194
},
195-
FloatIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name)),
195+
FloatIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name, generics)),
196196
FloatIrregularTrait::SerdeDeserialize => Ok(gen_impl_trait_serde_deserialize(
197197
type_name,
198+
generics,
198199
inner_type,
199200
maybe_error_type_name.as_ref(),
200201
)),

nutype_macros/src/integer/gen/traits/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,10 @@ fn gen_implemented_traits<T: ToTokens>(
214214
}
215215
}
216216
}
217-
IntegerIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name)),
217+
IntegerIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name, generics)),
218218
IntegerIrregularTrait::SerdeDeserialize => Ok(gen_impl_trait_serde_deserialize(
219219
type_name,
220+
generics,
220221
inner_type,
221222
maybe_error_type_name.as_ref(),
222223
)),

nutype_macros/src/string/gen/traits/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,10 @@ fn gen_implemented_traits(
210210
Err(syn::Error::new(span, msg))
211211
}
212212
},
213-
StringIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name)),
213+
StringIrregularTrait::SerdeSerialize => Ok(gen_impl_trait_serde_serialize(type_name, generics)),
214214
StringIrregularTrait::SerdeDeserialize => Ok(gen_impl_trait_serde_deserialize(
215215
type_name,
216+
generics,
216217
inner_type,
217218
maybe_error_type_name.as_ref(),
218219
)),

test_suite/tests/any.rs

+47
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,53 @@ mod traits {
329329
assert_eq!(deserialized, place);
330330
}
331331
}
332+
333+
mod with_generics {
334+
use super::*;
335+
336+
// TODO: Uncomment when https://github.com/greyblake/nutype/issues/142 is fixed
337+
// #[test]
338+
// fn test_generic_with_serde() {
339+
// #[nutype(
340+
// derive(Debug, Serialize, Deserialize),
341+
// validate(predicate = |v| v.is_empty())
342+
// )]
343+
// struct EmptyVec<T>(Vec<T>);
344+
345+
// {
346+
// let vec = EmptyVec::new(vec![]);
347+
// let json = serde_json::to_string(&vec).unwrap();
348+
// assert_eq!(json, "[]");
349+
350+
// let same_vec: EmptyVec<u8> = serde_json::from_str(&json).unwrap();
351+
// assert_eq!(vec, same_vec);
352+
// }
353+
354+
// {
355+
// let vec = EmptyVec::new(vec![1, 2, 3]);
356+
// let err = serde_json::to_string(&vec).unwrap_err();
357+
// assert_eq!(
358+
// err.to_string(),
359+
// "EmptyVec failed the predicate test. Expected valid EmptyVec"
360+
// );
361+
// }
362+
// }
363+
364+
#[test]
365+
fn serialize_and_deserialize_cow() {
366+
#[nutype(
367+
validate(predicate = |s| s.len() >= 3),
368+
derive(Debug, Serialize, Deserialize, PartialEq)
369+
)]
370+
struct Clarabelle<'a>(Cow<'a, str>);
371+
372+
let muu = Clarabelle::new(Cow::Borrowed("Muu")).unwrap();
373+
let json = serde_json::to_string(&muu).unwrap();
374+
assert_eq!(json, "\"Muu\"");
375+
let same_muu: Clarabelle = serde_json::from_str(&json).unwrap();
376+
assert_eq!(muu, same_muu);
377+
}
378+
}
332379
}
333380
}
334381

0 commit comments

Comments
 (0)