Skip to content

Commit

Permalink
Merge pull request #37 from greyblake/try-from-without-validation
Browse files Browse the repository at this point in the history
Support TryFrom for types without validation
  • Loading branch information
greyblake authored Jun 23, 2023
2 parents cd8f0b5 + 1224614 commit aa812cf
Show file tree
Hide file tree
Showing 14 changed files with 69 additions and 55 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### v0.3.0 - 2023-??-??
* Add `finite` validation for float types which checks against NaN and infinity.
* Enable deriving of `Eq` and `Ord` on float types (if `finite` validation is present)
* Enable deriving of `TryFrom` for types without validation (in this case Error type is `std::convert::Infallible`)

### v0.2.0 - 2023-04-13

Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[workspace]

resolver = "2"

members = [
"nutype",
"nutype_macros",
Expand Down
33 changes: 26 additions & 7 deletions nutype_macros/src/common/gen/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,33 @@ pub fn gen_impl_trait_from(type_name: &TypeName, inner_type: impl ToTokens) -> T
pub fn gen_impl_trait_try_from(
type_name: &TypeName,
inner_type: impl ToTokens,
error_type_name: &ErrorTypeName,
maybe_error_type_name: Option<&ErrorTypeName>,
) -> TokenStream {
quote! {
impl ::core::convert::TryFrom<#inner_type> for #type_name {
type Error = #error_type_name;

fn try_from(raw_value: #inner_type) -> Result<#type_name, Self::Error> {
Self::new(raw_value)
match maybe_error_type_name {
Some(error_type_name) => {
// The case when there are validation
//
quote! {
impl ::core::convert::TryFrom<#inner_type> for #type_name {
type Error = #error_type_name;

fn try_from(raw_value: #inner_type) -> Result<#type_name, Self::Error> {
Self::new(raw_value)
}
}
}
}
None => {
// The case when there are no validation
//
quote! {
impl ::core::convert::TryFrom<#inner_type> for #type_name {
type Error = ::core::convert::Infallible;

fn try_from(raw_value: #inner_type) -> Result<#type_name, Self::Error> {
Ok(Self::new(raw_value))
}
}
}
}
}
Expand Down
5 changes: 1 addition & 4 deletions nutype_macros/src/float/gen/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,7 @@ fn gen_implemented_traits(
FloatIrregularTrait::From => gen_impl_trait_from(type_name, inner_type),
FloatIrregularTrait::Into => gen_impl_trait_into(type_name, inner_type),
FloatIrregularTrait::TryFrom => {
let error_type_name = maybe_error_type_name
.as_ref()
.expect("TryFrom for float is expected to have error_type_name");
gen_impl_trait_try_from(type_name, inner_type, error_type_name)
gen_impl_trait_try_from(type_name, inner_type, maybe_error_type_name.as_ref())
}
FloatIrregularTrait::Borrow => gen_impl_trait_borrow(type_name, inner_type),
FloatIrregularTrait::Display => gen_impl_trait_dislpay(type_name),
Expand Down
8 changes: 1 addition & 7 deletions nutype_macros/src/float/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,7 @@ fn to_float_derive_trait(
Ok(FloatDeriveTrait::From)
}
}
NormalDeriveTrait::TryFrom => {
if validation.has_validation {
Ok(FloatDeriveTrait::TryFrom)
} else {
Err(syn::Error::new(span, "#[nutype] cannot derive `TryFrom`, because there is no validation. Use `From` instead."))
}
}
NormalDeriveTrait::TryFrom => Ok(FloatDeriveTrait::TryFrom),
NormalDeriveTrait::SerdeSerialize => Ok(FloatDeriveTrait::SerdeSerialize),
NormalDeriveTrait::SerdeDeserialize => Ok(FloatDeriveTrait::SerdeDeserialize),
NormalDeriveTrait::SchemarsJsonSchema => Ok(FloatDeriveTrait::SchemarsJsonSchema),
Expand Down
5 changes: 1 addition & 4 deletions nutype_macros/src/integer/gen/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,7 @@ fn gen_implemented_traits(
IntegerIrregularTrait::From => gen_impl_trait_from(type_name, inner_type),
IntegerIrregularTrait::Into => gen_impl_trait_into(type_name, inner_type),
IntegerIrregularTrait::TryFrom => {
let error_type_name = maybe_error_type_name
.as_ref()
.expect("TryFrom for integer is expected to have error_type_name");
gen_impl_trait_try_from(type_name, inner_type, error_type_name)
gen_impl_trait_try_from(type_name, inner_type, maybe_error_type_name.as_ref())
}
IntegerIrregularTrait::Borrow => gen_impl_trait_borrow(type_name, inner_type),
IntegerIrregularTrait::Display => gen_impl_trait_dislpay(type_name),
Expand Down
8 changes: 1 addition & 7 deletions nutype_macros/src/integer/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,19 +152,13 @@ fn to_integer_derive_trait(
NormalDeriveTrait::SerdeSerialize => Ok(IntegerDeriveTrait::SerdeSerialize),
NormalDeriveTrait::SerdeDeserialize => Ok(IntegerDeriveTrait::SerdeDeserialize),
NormalDeriveTrait::SchemarsJsonSchema => Ok(IntegerDeriveTrait::SchemarsJsonSchema),
NormalDeriveTrait::TryFrom => Ok(IntegerDeriveTrait::TryFrom),
NormalDeriveTrait::From => {
if has_validation {
Err(syn::Error::new(span, "#[nutype] cannot derive `From` trait, because there is validation defined. Use `TryFrom` instead."))
} else {
Ok(IntegerDeriveTrait::From)
}
}
NormalDeriveTrait::TryFrom => {
if has_validation {
Ok(IntegerDeriveTrait::TryFrom)
} else {
Err(syn::Error::new(span, "#[nutype] cannot derive `TryFrom`, because there is no validation. Use `From` instead."))
}
}
}
}
15 changes: 8 additions & 7 deletions nutype_macros/src/string/gen/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,7 @@ fn gen_implemented_traits(
StringIrregularTrait::From => gen_impl_from_str_and_string(type_name),
StringIrregularTrait::Into => gen_impl_trait_into(type_name, inner_type),
StringIrregularTrait::TryFrom => {
let error_type_name = maybe_error_type_name
.as_ref()
.expect("TryFrom for String is expected to have error_type_name");
gen_impl_try_from(type_name, error_type_name)
gen_impl_try_from(type_name, maybe_error_type_name.as_ref())
}
StringIrregularTrait::Borrow => gen_impl_borrow_str_and_string(type_name),
StringIrregularTrait::Display => gen_impl_trait_dislpay(type_name),
Expand Down Expand Up @@ -216,9 +213,13 @@ fn gen_impl_from_str_and_string(type_name: &TypeName) -> TokenStream {
}
}

fn gen_impl_try_from(type_name: &TypeName, error_type_name: &ErrorTypeName) -> TokenStream {
let impl_try_from_string = gen_impl_trait_try_from(type_name, quote!(String), error_type_name);
let impl_try_from_str = gen_impl_trait_try_from(type_name, quote!(&str), error_type_name);
fn gen_impl_try_from(
type_name: &TypeName,
maybe_error_type_name: Option<&ErrorTypeName>,
) -> TokenStream {
let impl_try_from_string =
gen_impl_trait_try_from(type_name, quote!(String), maybe_error_type_name);
let impl_try_from_str = gen_impl_trait_try_from(type_name, quote!(&str), maybe_error_type_name);

quote! {
#impl_try_from_string
Expand Down
8 changes: 1 addition & 7 deletions nutype_macros/src/string/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,7 @@ fn to_string_derive_trait(
Ok(StringDeriveTrait::From)
}
}
NormalDeriveTrait::TryFrom => {
if has_validation {
Ok(StringDeriveTrait::TryFrom)
} else {
Err(syn::Error::new(span, "#[nutype] cannot derive `TryFrom`, because there is no validation. Use `From` instead."))
}
}
NormalDeriveTrait::TryFrom => Ok(StringDeriveTrait::TryFrom),
}
}

Expand Down
9 changes: 9 additions & 0 deletions test_suite/tests/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ mod validators {
assert_eq!(Age::try_from(18.0).unwrap().into_inner(), 18.0);
}

#[test]
fn test_try_from_trait_without_validation() {
#[nutype]
#[derive(Debug, PartialEq, TryFrom)]
struct Age(f64);

assert_eq!(Age::try_from(78.8).unwrap().into_inner(), 78.8);
}

#[cfg(test)]
mod error {
use super::*;
Expand Down
9 changes: 9 additions & 0 deletions test_suite/tests/integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ mod validators {
assert_eq!(Age::try_from(18).unwrap().into_inner(), 18);
}

#[test]
fn test_try_from_trait_without_validation() {
#[nutype]
#[derive(Debug, PartialEq, TryFrom)]
struct Age(u8);

assert_eq!(Age::try_from(78).unwrap().into_inner(), 78);
}

#[cfg(test)]
mod error {
use super::*;
Expand Down
9 changes: 9 additions & 0 deletions test_suite/tests/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ mod validators {
assert_eq!(Name::try_from("Tom").unwrap().into_inner(), "Tom");
}

#[test]
fn test_try_from_trait_without_validation() {
#[nutype]
#[derive(Debug, PartialEq, TryFrom)]
pub struct Name(String);

assert_eq!(Name::try_from("Tom").unwrap().into_inner(), "Tom");
}

#[test]
fn test_error() {
fn ensure_type_implements_error<T: std::error::Error>() {}
Expand Down
7 changes: 0 additions & 7 deletions test_suite/tests/ui/string/derive/try_from.rs

This file was deleted.

5 changes: 0 additions & 5 deletions test_suite/tests/ui/string/derive/try_from.stderr

This file was deleted.

0 comments on commit aa812cf

Please sign in to comment.