Skip to content

Commit

Permalink
Merge pull request #187 from greyblake/error-path
Browse files Browse the repository at this point in the history
Error path
  • Loading branch information
greyblake authored Sep 21, 2024
2 parents aad0699 + acbe913 commit 3401f2c
Show file tree
Hide file tree
Showing 23 changed files with 223 additions and 179 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### v0.x.x - 202x-xx-xx

* **[FIX]** Enable to specify custom error as a path (see [#186](https://github.com/greyblake/nutype/issues/186), [#187](https://github.com/greyblake/nutype/pull/187))

### v0.5.0 - 2024-xx-xx

- **[FEATURE]** Added support for custom error types and validation functions via the `error` and `with` attributes.
Expand Down
20 changes: 10 additions & 10 deletions nutype_macros/src/any/gen/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ use crate::{
any::models::AnyValidator,
common::{
gen::error::gen_impl_error_trait,
models::{ErrorTypeName, TypeName},
models::{ErrorTypePath, TypeName},
},
};

pub fn gen_validation_error_type(
type_name: &TypeName,
error_type_name: &ErrorTypeName,
error_type_path: &ErrorTypePath,
validators: &[AnyValidator],
) -> TokenStream {
let definition = gen_definition(error_type_name, validators);
let impl_display_trait = gen_impl_display_trait(type_name, error_type_name, validators);
let impl_error_trait = gen_impl_error_trait(error_type_name);
let definition = gen_definition(error_type_path, validators);
let impl_display_trait = gen_impl_display_trait(type_name, error_type_path, validators);
let impl_error_trait = gen_impl_error_trait(error_type_path);

quote! {
#[derive(Debug, Clone, PartialEq, Eq)]
Expand All @@ -27,7 +27,7 @@ pub fn gen_validation_error_type(
}
}

fn gen_definition(error_type_name: &ErrorTypeName, validators: &[AnyValidator]) -> TokenStream {
fn gen_definition(error_type_path: &ErrorTypePath, validators: &[AnyValidator]) -> TokenStream {
let error_variants: TokenStream = validators
.iter()
.map(|validator| match validator {
Expand All @@ -39,25 +39,25 @@ fn gen_definition(error_type_name: &ErrorTypeName, validators: &[AnyValidator])

quote! {
#[allow(clippy::enum_variant_names)]
pub enum #error_type_name {
pub enum #error_type_path {
#error_variants
}
}
}

fn gen_impl_display_trait(
type_name: &TypeName,
error_type_name: &ErrorTypeName,
error_type_path: &ErrorTypePath,
validators: &[AnyValidator],
) -> TokenStream {
let match_arms = validators.iter().map(|validator| match validator {
AnyValidator::Predicate(_) => quote! {
#error_type_name::PredicateViolated => write!(f, "{} failed the predicate test.", stringify!(#type_name))
#error_type_path::PredicateViolated => write!(f, "{} failed the predicate test.", stringify!(#type_name))
},
});

quote! {
impl ::core::fmt::Display for #error_type_name {
impl ::core::fmt::Display for #error_type_path {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
match self {
#(#match_arms,)*
Expand Down
12 changes: 6 additions & 6 deletions nutype_macros/src/any/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::common::{
gen::{
tests::gen_test_should_have_valid_default_value, traits::GeneratedTraits, GenerateNewtype,
},
models::{ErrorTypeName, Guard, TypeName, TypedCustomFunction},
models::{ErrorTypePath, Guard, TypeName, TypedCustomFunction},
};

use self::error::gen_validation_error_type;
Expand Down Expand Up @@ -61,7 +61,7 @@ impl GenerateNewtype for AnyNewtype {

fn gen_fn_validate(
inner_type: &Self::InnerType,
error_type_name: &ErrorTypeName,
error_type_path: &ErrorTypePath,
validators: &[Self::Validator],
) -> TokenStream {
let validations: TokenStream = validators
Expand All @@ -77,7 +77,7 @@ impl GenerateNewtype for AnyNewtype {
.expect("Failed to convert predicate into a typed closure");
quote!(
if !(#typed_predicate)(val) {
return Err(#error_type_name::PredicateViolated);
return Err(#error_type_path::PredicateViolated);
}
)
}
Expand All @@ -98,7 +98,7 @@ impl GenerateNewtype for AnyNewtype {
// Since this code is generic which is used for different inner types (not only Cow), we cannot easily fix it to make
// clippy happy.
#[allow(clippy::ptr_arg)]
fn __validate__<'nutype_a>(val: &'nutype_a #inner_type) -> ::core::result::Result<(), #error_type_name> {
fn __validate__<'nutype_a>(val: &'nutype_a #inner_type) -> ::core::result::Result<(), #error_type_path> {
#validations
Ok(())
}
Expand All @@ -107,10 +107,10 @@ impl GenerateNewtype for AnyNewtype {

fn gen_validation_error_type(
type_name: &TypeName,
error_type_name: &ErrorTypeName,
error_type_path: &ErrorTypePath,
validators: &[Self::Validator],
) -> TokenStream {
gen_validation_error_type(type_name, error_type_name, validators)
gen_validation_error_type(type_name, error_type_path, validators)
}

fn gen_traits(
Expand Down
2 changes: 1 addition & 1 deletion nutype_macros/src/any/gen/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ fn gen_implemented_traits(
maybe_default_value: Option<syn::Expr>,
guard: &AnyGuard,
) -> Result<TokenStream, syn::Error> {
let maybe_error_type_name = guard.maybe_error_type_name();
let maybe_error_type_name = guard.maybe_error_type_path();
impl_traits
.iter()
.map(|t| match t {
Expand Down
10 changes: 5 additions & 5 deletions nutype_macros/src/common/gen/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@ use cfg_if::cfg_if;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

use crate::common::models::{ErrorTypeName, TypeName};
use crate::common::models::{ErrorTypePath, TypeName};

/// Generate a default error type name if the error name is not specified explicitly by
/// the user in the attributes.
pub fn gen_error_type_name(type_name: &TypeName) -> ErrorTypeName {
pub fn gen_error_type_name(type_name: &TypeName) -> ErrorTypePath {
let ident = format_ident!("{type_name}Error");
ErrorTypeName::new(ident)
ErrorTypePath::new(ident)
}

// NOTE: There is no `::core::error::Error` yet in stable Rust.
// So for `no_std` we just don't implement `Error` trait.
#[allow(unused_variables)]
pub fn gen_impl_error_trait(error_type_name: &ErrorTypeName) -> TokenStream {
pub fn gen_impl_error_trait(error_type_path: &ErrorTypePath) -> TokenStream {
cfg_if! {
if #[cfg(feature = "std")] {
quote! {
impl ::std::error::Error for #error_type_name {
impl ::std::error::Error for #error_type_path {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
None
}
Expand Down
52 changes: 26 additions & 26 deletions nutype_macros/src/common/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{collections::HashSet, hash::Hash};
use self::traits::GeneratedTraits;

use super::models::{
CustomFunction, ErrorTypeName, GenerateParams, Guard, NewUnchecked, ParseErrorTypeName,
CustomFunction, ErrorTypePath, GenerateParams, Guard, NewUnchecked, ParseErrorTypeName,
TypeName, TypeTrait,
};
use crate::common::{
Expand Down Expand Up @@ -99,27 +99,27 @@ pub fn gen_reimports(
vis: Visibility,
type_name: &TypeName,
module_name: &ModuleName,
maybe_error_type_name: Option<&ErrorTypeName>,
maybe_error_type_path: Option<&ErrorTypePath>,
maybe_parse_error_type_name: Option<&ParseErrorTypeName>,
) -> TokenStream {
let reimport_main_type = quote! {
#vis use #module_name::#type_name;
};

let reimport_error_type_if_needed = match maybe_error_type_name {
let reimport_error_type_if_needed = match maybe_error_type_path {
None => quote!(),
Some(ref error_type_name) => {
Some(ref error_type_path) => {
quote! (
#vis use #module_name::#error_type_name;
#vis use #module_name::#error_type_path;
)
}
};

let reimport_parse_error_type_if_needed = match maybe_parse_error_type_name {
None => quote!(),
Some(ref parse_error_type_name) => {
Some(ref parse_error_type_path) => {
quote! (
#vis use #module_name::#parse_error_type_name;
#vis use #module_name::#parse_error_type_path;
)
}
};
Expand Down Expand Up @@ -224,13 +224,13 @@ pub trait GenerateNewtype {

fn gen_fn_validate(
inner_type: &Self::InnerType,
error_type_name: &ErrorTypeName,
error_type_path: &ErrorTypePath,
validators: &[Self::Validator],
) -> TokenStream;

fn gen_validation_error_type(
type_name: &TypeName,
error_type_name: &ErrorTypeName,
error_type_path: &ErrorTypePath,
validators: &[Self::Validator],
) -> TokenStream;

Expand All @@ -256,10 +256,10 @@ pub trait GenerateNewtype {
let maybe_generated_validation_error = match validation {
Validation::Standard {
validators,
error_type_name,
error_type_path,
} => {
let validation_error =
Self::gen_validation_error_type(type_name, error_type_name, validators);
Self::gen_validation_error_type(type_name, error_type_path, validators);
Some(validation_error)
}
Validation::Custom { .. } => None,
Expand All @@ -268,12 +268,12 @@ pub trait GenerateNewtype {
let fn_validate = match validation {
Validation::Standard {
validators,
error_type_name,
} => Self::gen_fn_validate(inner_type, error_type_name, validators),
error_type_path,
} => Self::gen_fn_validate(inner_type, error_type_path, validators),
Validation::Custom {
with,
error_type_name,
} => gen_fn_validate_custom(inner_type, with, error_type_name),
error_type_path,
} => gen_fn_validate_custom(inner_type, with, error_type_path),
};

let (input_type, convert_raw_value_if_necessary) = if Self::NEW_CONVERT_INTO_INNER_TYPE {
Expand All @@ -285,13 +285,13 @@ pub trait GenerateNewtype {
(quote!(#inner_type), quote!())
};

let error_type_name = validation.error_type_name();
let error_type_path = validation.error_type_path();

quote!(
#maybe_generated_validation_error

impl #generics #type_name #generics_without_bounds {
pub fn try_new(raw_value: #input_type) -> ::core::result::Result<Self, #error_type_name> {
pub fn try_new(raw_value: #input_type) -> ::core::result::Result<Self, #error_type_path> {
#convert_raw_value_if_necessary

let sanitized_value: #inner_type = Self::__sanitize__(raw_value);
Expand All @@ -306,7 +306,7 @@ pub trait GenerateNewtype {

// TODO: Remove in 0.5.0
#[deprecated(since="0.4.3", note="\nUse `try_new` instead.")]
pub fn new(raw_value: #input_type) -> ::core::result::Result<Self, #error_type_name> {
pub fn new(raw_value: #input_type) -> ::core::result::Result<Self, #error_type_path> {
Self::try_new(raw_value)
}
}
Expand Down Expand Up @@ -395,7 +395,7 @@ pub trait GenerateNewtype {
Self::gen_implementation(&type_name, &generics, &inner_type, &guard, new_unchecked);

let has_from_str_trait = traits.iter().any(|t| t.is_from_str());
let maybe_parse_error_type_name = if has_from_str_trait && Self::HAS_DEDICATED_PARSE_ERROR {
let maybe_parse_error_type_path = if has_from_str_trait && Self::HAS_DEDICATED_PARSE_ERROR {
Some(gen_parse_error_name(&type_name))
} else {
None
Expand All @@ -410,23 +410,23 @@ pub trait GenerateNewtype {
&traits,
);

let maybe_reimported_error_type_name = match &guard {
let maybe_reimported_error_type_path = match &guard {
Guard::WithoutValidation { .. } => None,
Guard::WithValidation { validation, .. } => match validation {
// We won't need to reimport error if it's a custom error provided by the user.
Validation::Custom { .. } => None,
Validation::Standard {
error_type_name, ..
} => Some(error_type_name),
error_type_path, ..
} => Some(error_type_path),
},
};

let reimports = gen_reimports(
vis,
&type_name,
&module_name,
maybe_reimported_error_type_name,
maybe_parse_error_type_name.as_ref(),
maybe_reimported_error_type_path,
maybe_parse_error_type_path.as_ref(),
);

let GeneratedTraits {
Expand Down Expand Up @@ -472,13 +472,13 @@ pub trait GenerateNewtype {
fn gen_fn_validate_custom<InnerType: ToTokens>(
inner_type: &InnerType,
with: &CustomFunction,
error_type_name: &ErrorTypeName,
error_type_path: &ErrorTypePath,
) -> TokenStream {
quote! {
// For some types like `String` clippy suggests using `&str` instead of `&String` here,
// but it does not really matter in this context.
#[allow(clippy::ptr_arg)]
fn __validate__(value: &#inner_type) -> ::core::result::Result<(), #error_type_name> {
fn __validate__(value: &#inner_type) -> ::core::result::Result<(), #error_type_path> {
#with(value)
}
}
Expand Down
4 changes: 2 additions & 2 deletions nutype_macros/src/common/gen/parse_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use syn::Generics;

use crate::common::{
gen::{add_bound_to_all_type_params, strip_trait_bounds_on_generics},
models::{ErrorTypeName, InnerType, ParseErrorTypeName, TypeName},
models::{ErrorTypePath, InnerType, ParseErrorTypeName, TypeName},
};

/// Generate a name for the error which is used for FromStr trait implementation.
Expand All @@ -20,7 +20,7 @@ pub fn gen_def_parse_error(
type_name: &TypeName,
generics: &Generics,
inner_type: impl Into<InnerType>,
maybe_error_type_name: Option<&ErrorTypeName>,
maybe_error_type_name: Option<&ErrorTypePath>,
parse_error_type_name: &ParseErrorTypeName,
) -> TokenStream {
let inner_type: InnerType = inner_type.into();
Expand Down
8 changes: 4 additions & 4 deletions nutype_macros/src/common/gen/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use syn::Generics;

use crate::common::{
gen::{add_bound_to_all_type_params, strip_trait_bounds_on_generics},
models::{ErrorTypeName, InnerType, TypeName},
models::{ErrorTypePath, InnerType, TypeName},
};

use super::parse_error::{gen_def_parse_error, gen_parse_error_name};
Expand Down Expand Up @@ -172,7 +172,7 @@ pub fn gen_impl_trait_try_from(
type_name: &TypeName,
generics: &Generics,
inner_type: impl ToTokens,
maybe_error_type_name: Option<&ErrorTypeName>,
maybe_error_type_name: Option<&ErrorTypePath>,
) -> TokenStream {
let generics_without_bounds = strip_trait_bounds_on_generics(generics);

Expand Down Expand Up @@ -213,7 +213,7 @@ pub fn gen_impl_trait_from_str(
type_name: &TypeName,
generics: &Generics,
inner_type: impl Into<InnerType>,
maybe_error_type_name: Option<&ErrorTypeName>,
maybe_error_type_name: Option<&ErrorTypePath>,
) -> TokenStream {
let inner_type: InnerType = inner_type.into();
let parse_error_type_name = gen_parse_error_name(type_name);
Expand Down Expand Up @@ -286,7 +286,7 @@ pub fn gen_impl_trait_serde_deserialize(
type_name: &TypeName,
type_generics: &Generics,
inner_type: impl Into<InnerType>,
maybe_error_type_name: Option<&ErrorTypeName>,
maybe_error_type_name: Option<&ErrorTypePath>,
) -> TokenStream {
let inner_type: InnerType = inner_type.into();
let raw_value_to_result: TokenStream = if maybe_error_type_name.is_some() {
Expand Down
Loading

0 comments on commit 3401f2c

Please sign in to comment.