diff --git a/dummy/src/main.rs b/dummy/src/main.rs index a0b41f8..e775404 100644 --- a/dummy/src/main.rs +++ b/dummy/src/main.rs @@ -26,23 +26,6 @@ enum NameError { derive(Debug, AsRef, PartialEq, Deref), )] struct Name(String); - -// Variant 2: `custom` and `custom_error` -#[nutype( - sanitize(trim), - validate(custom = validate_name, custom_error = NameError), - derive(Debug, AsRef, PartialEq, Deref), -)] -struct Name(String); - -// Variant 3: -#[nutype( - sanitize(trim), - validate(with = validate_name), - derive(Debug, AsRef, PartialEq, Deref), - error = NameError, -)] -struct Name(String); */ fn main() {} diff --git a/nutype_macros/src/common/gen/mod.rs b/nutype_macros/src/common/gen/mod.rs index 86e0f19..5dae0c3 100644 --- a/nutype_macros/src/common/gen/mod.rs +++ b/nutype_macros/src/common/gen/mod.rs @@ -13,7 +13,7 @@ use super::models::{ }; use crate::common::{ gen::{new_unchecked::gen_new_unchecked, parse_error::gen_parse_error_name}, - models::ModuleName, + models::{ModuleName, Validation}, }; use proc_macro2::{Punct, Spacing, TokenStream, TokenTree}; use quote::{format_ident, quote, ToTokens}; @@ -335,16 +335,20 @@ pub trait GenerateNewtype { } Guard::WithValidation { sanitizers, - validators, - error_type_name, - } => Self::gen_try_new( - type_name, - generics, - inner_type, - sanitizers, - validators, - error_type_name, - ), + validation, + } => match validation { + Validation::Standard { + validators, + error_type_name, + } => Self::gen_try_new( + type_name, + generics, + inner_type, + sanitizers, + validators, + error_type_name, + ), + }, }; let impl_into_inner = gen_impl_into_inner(type_name, generics, inner_type); let impl_new_unchecked = gen_new_unchecked(type_name, inner_type, new_unchecked); @@ -396,12 +400,7 @@ pub trait GenerateNewtype { &traits, ); - let maybe_error_type_name = match &guard { - Guard::WithValidation { - error_type_name, .. - } => Some(error_type_name), - Guard::WithoutValidation { .. } => None, - }; + let maybe_error_type_name = guard.maybe_error_type_name(); let reimports = gen_reimports( vis, diff --git a/nutype_macros/src/common/models.rs b/nutype_macros/src/common/models.rs index 0a194ed..d965e2f 100644 --- a/nutype_macros/src/common/models.rs +++ b/nutype_macros/src/common/models.rs @@ -210,8 +210,20 @@ pub enum Guard { }, WithValidation { sanitizers: Vec, - validators: Vec, + validation: Validation, + }, +} + +#[derive(Debug)] +pub enum Validation { + // TODO: + // Custom { + // with: TypedCustomFunction, + // error_type_name: ErrorTypeName, + // }, + Standard { error_type_name: ErrorTypeName, + validators: Vec, }, } @@ -219,9 +231,11 @@ impl Guard { pub fn maybe_error_type_name(&self) -> Option<&ErrorTypeName> { match self { Self::WithoutValidation { .. } => None, - Self::WithValidation { - error_type_name, .. - } => Some(error_type_name), + Self::WithValidation { validation, .. } => match validation { + Validation::Standard { + error_type_name, .. + } => Some(error_type_name), + }, } } } @@ -291,7 +305,9 @@ impl Guard { pub fn validators(&self) -> Option<&Vec> { match self { - Self::WithValidation { validators, .. } => Some(validators), + Self::WithValidation { validation, .. } => match validation { + Validation::Standard { validators, .. } => Some(validators), + }, Self::WithoutValidation { .. } => None, } } diff --git a/nutype_macros/src/common/validate.rs b/nutype_macros/src/common/validate.rs index 81fbc73..1597025 100644 --- a/nutype_macros/src/common/validate.rs +++ b/nutype_macros/src/common/validate.rs @@ -4,7 +4,7 @@ use proc_macro2::Span; use super::{ models::{ DeriveTrait, Guard, NumericBoundValidator, RawGuard, SpannedDeriveTrait, SpannedItem, - TypeName, + TypeName, Validation, }, r#gen::error::gen_error_type_name, }; @@ -35,8 +35,10 @@ pub fn validate_guard( let error_type_name = error_type_name.unwrap_or_else(|| gen_error_type_name(type_name)); Ok(Guard::WithValidation { sanitizers, - validators, - error_type_name, + validation: Validation::Standard { + validators, + error_type_name, + }, }) } } diff --git a/nutype_macros/src/float/gen/traits/arbitrary.rs b/nutype_macros/src/float/gen/traits/arbitrary.rs index 2b95a0c..254102e 100644 --- a/nutype_macros/src/float/gen/traits/arbitrary.rs +++ b/nutype_macros/src/float/gen/traits/arbitrary.rs @@ -2,7 +2,7 @@ use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use crate::{ - common::models::TypeName, + common::models::{TypeName, Validation}, float::models::{ FloatGuard, FloatInnerType, FloatSanitizer, FloatSanitizerKind, FloatValidator, FloatValidatorKind, @@ -65,11 +65,16 @@ fn gen_generate_valid_inner_value( } FloatGuard::WithValidation { sanitizers, - validators, - error_type_name: _, + validation, } => { - // When there is validation, then we need to generate a valid value. - gen_generate_valid_inner_value_with_validators(inner_type, sanitizers, validators) + match validation { + Validation::Standard { validators, .. } => { + // When there is validation, then we need to generate a valid value. + gen_generate_valid_inner_value_with_validators( + inner_type, sanitizers, validators, + ) + } + } } } } diff --git a/nutype_macros/src/float/validate.rs b/nutype_macros/src/float/validate.rs index 6cf5307..93b32cd 100644 --- a/nutype_macros/src/float/validate.rs +++ b/nutype_macros/src/float/validate.rs @@ -2,7 +2,7 @@ use proc_macro2::Span; use std::collections::HashSet; use crate::common::{ - models::{DeriveTrait, SpannedDeriveTrait, TypeName}, + models::{DeriveTrait, SpannedDeriveTrait, TypeName, Validation}, validate::{ validate_duplicates, validate_guard, validate_numeric_bounds, validate_traits_from_xor_try_from, @@ -64,9 +64,11 @@ where fn has_validation_against_nan(guard: &FloatGuard) -> bool { match guard { FloatGuard::WithoutValidation { .. } => false, - FloatGuard::WithValidation { ref validators, .. } => validators - .iter() - .any(|v| v.kind() == FloatValidatorKind::Finite), + FloatGuard::WithValidation { validation, .. } => match validation { + Validation::Standard { validators, .. } => validators + .iter() + .any(|v| v.kind() == FloatValidatorKind::Finite), + }, } } diff --git a/nutype_macros/src/integer/gen/traits/arbitrary.rs b/nutype_macros/src/integer/gen/traits/arbitrary.rs index afe54ad..0701d23 100644 --- a/nutype_macros/src/integer/gen/traits/arbitrary.rs +++ b/nutype_macros/src/integer/gen/traits/arbitrary.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use crate::{ - common::models::TypeName, + common::models::{TypeName, Validation}, integer::models::{IntegerGuard, IntegerInnerType, IntegerValidator}, utils::issue_reporter::{build_github_link_with_issue, Issue}, }; @@ -66,31 +66,37 @@ fn guard_to_boundary( } IntegerGuard::WithValidation { sanitizers: _, - validators, - error_type_name: _, + validation, } => { - // Apply the validators to the boundaries. - // Since the validators were already validated, it's guaranteed that they're not - // contradicting each other. - for validator in validators { - match validator { - IntegerValidator::Greater(gt) => { - boundary.min = quote!(#gt + 1); - } - IntegerValidator::GreaterOrEqual(gte) => { - boundary.min = quote!(#gte); - } - IntegerValidator::Less(lt) => { - boundary.max = quote!(#lt - 1); - } - IntegerValidator::LessOrEqual(lte) => { - boundary.max = quote!(#lte); - } - IntegerValidator::Predicate(_) => { - return Err(syn::Error::new( - proc_macro2::Span::call_site(), - "Cannot derive trait `Arbitrary` for a type with `predicate` validator", - )); + match validation { + Validation::Standard { + validators, + error_type_name: _, + } => { + // Apply the validators to the boundaries. + // Since the validators were already validated, it's guaranteed that they're not + // contradicting each other. + for validator in validators { + match validator { + IntegerValidator::Greater(gt) => { + boundary.min = quote!(#gt + 1); + } + IntegerValidator::GreaterOrEqual(gte) => { + boundary.min = quote!(#gte); + } + IntegerValidator::Less(lt) => { + boundary.max = quote!(#lt - 1); + } + IntegerValidator::LessOrEqual(lte) => { + boundary.max = quote!(#lte); + } + IntegerValidator::Predicate(_) => { + return Err(syn::Error::new( + proc_macro2::Span::call_site(), + "Cannot derive trait `Arbitrary` for a type with `predicate` validator", + )); + } + } } } } diff --git a/nutype_macros/src/string/gen/traits/arbitrary.rs b/nutype_macros/src/string/gen/traits/arbitrary.rs index da16f17..6811783 100644 --- a/nutype_macros/src/string/gen/traits/arbitrary.rs +++ b/nutype_macros/src/string/gen/traits/arbitrary.rs @@ -3,7 +3,7 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use crate::{ - common::models::{TypeName, ValueOrExpr}, + common::models::{TypeName, Validation, ValueOrExpr}, string::models::{StringGuard, StringSanitizer, StringValidator}, utils::issue_reporter::{build_github_link_with_issue, Issue}, }; @@ -110,9 +110,10 @@ fn build_specification(guard: &StringGuard) -> Result, syn StringGuard::WithoutValidation { .. } => Ok(None), StringGuard::WithValidation { sanitizers, - validators, - error_type_name: _, + validation, } => { + let validators = get_validators(validation); + let relevant_sanitizers = filter_sanitizers(sanitizers)?; let relevant_validators = filter_validators(validators)?; @@ -150,6 +151,12 @@ fn build_specification(guard: &StringGuard) -> Result, syn } } +fn get_validators(validation: &Validation) -> &[StringValidator] { + match validation { + Validation::Standard { validators, .. } => validators, + } +} + fn filter_validators(validators: &[StringValidator]) -> Result, syn::Error> { validators.iter().map(|v| { match v { diff --git a/nutype_macros/src/string/models.rs b/nutype_macros/src/string/models.rs index a0b3f42..9d95a00 100644 --- a/nutype_macros/src/string/models.rs +++ b/nutype_macros/src/string/models.rs @@ -33,6 +33,8 @@ pub enum StringValidator { Predicate(TypedCustomFunction), #[cfg_attr(not(feature = "regex"), allow(dead_code))] Regex(RegexDef), + // With(TypedCustomFunction), + // Error(ErrorTypeName), } #[cfg_attr(not(feature = "regex"), allow(dead_code))]