Skip to content

Commit

Permalink
Support derive(TryFrom) with generics
Browse files Browse the repository at this point in the history
  • Loading branch information
greyblake committed Jun 23, 2024
1 parent 240c7ed commit 346122e
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
10 changes: 6 additions & 4 deletions nutype_macros/src/common/gen/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,18 @@ pub fn gen_impl_trait_try_from(
inner_type: impl ToTokens,
maybe_error_type_name: Option<&ErrorTypeName>,
) -> TokenStream {
let generics_without_bounds = strip_trait_bounds_on_generics(generics);

match maybe_error_type_name {
Some(error_type_name) => {
// The case when there are validation
//
quote! {
impl #generics ::core::convert::TryFrom<#inner_type> for #type_name #generics {
impl #generics ::core::convert::TryFrom<#inner_type> for #type_name #generics_without_bounds {
type Error = #error_type_name;

#[inline]
fn try_from(raw_value: #inner_type) -> ::core::result::Result<#type_name #generics, Self::Error> {
fn try_from(raw_value: #inner_type) -> ::core::result::Result<#type_name #generics_without_bounds, Self::Error> {
Self::new(raw_value)
}
}
Expand All @@ -185,11 +187,11 @@ pub fn gen_impl_trait_try_from(
// The case when there are no validation
//
quote! {
impl #generics ::core::convert::TryFrom<#inner_type> for #type_name #generics {
impl #generics ::core::convert::TryFrom<#inner_type> for #type_name #generics_without_bounds {
type Error = ::core::convert::Infallible;

#[inline]
fn try_from(raw_value: #inner_type) -> ::core::result::Result<#type_name #generics, Self::Error> {
fn try_from(raw_value: #inner_type) -> ::core::result::Result<#type_name #generics_without_bounds, Self::Error> {
Ok(Self::new(raw_value))
}
}
Expand Down
36 changes: 36 additions & 0 deletions test_suite/tests/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,9 +665,45 @@ mod with_generics {
}
}

#[test]
fn test_generic_boundaries_try_from_without_validation() {
// Note, that we get TryFrom thanks to the blanket implementation in core:
//
// impl<T, U> TryFrom<U> for T
// where
// U: Into<T>
//
#[nutype(derive(Debug, From))]
struct Doener<T>(T);

let durum = Doener::try_from("Durum").unwrap();
assert_eq!(durum.into_inner(), "Durum");
}

#[test]
fn test_generic_boundaries_try_from_with_validation() {
#[nutype(
derive(Debug, TryFrom),
validate(predicate = |v| !v.is_empty())
)]
struct NotEmpty<T>(Vec<T>);
{
let err = NotEmpty::<i32>::try_from(vec![]).unwrap_err();
assert_eq!(err, NotEmptyError::PredicateViolated);
}
{
let v = NotEmpty::try_from(vec![1, 2, 3]).unwrap();
assert_eq!(v.into_inner(), vec![1, 2, 3]);
}
}

#[test]
fn test_generic_boundaries_from_str() {
// TODO
// #[nutype(
// derive(Debug, FromStr),
// )]
// struct Wrapper<T>(T);
}

#[test]
Expand Down

0 comments on commit 346122e

Please sign in to comment.