Skip to content

Commit

Permalink
Introduce Validation enum
Browse files Browse the repository at this point in the history
  • Loading branch information
greyblake committed Aug 10, 2024
1 parent d06ff61 commit 97d5bad
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 79 deletions.
17 changes: 0 additions & 17 deletions dummy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
33 changes: 16 additions & 17 deletions nutype_macros/src/common/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
26 changes: 21 additions & 5 deletions nutype_macros/src/common/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,32 @@ pub enum Guard<Sanitizer, Validator> {
},
WithValidation {
sanitizers: Vec<Sanitizer>,
validators: Vec<Validator>,
validation: Validation<Validator>,
},
}

#[derive(Debug)]
pub enum Validation<Validator> {
// TODO:
// Custom {
// with: TypedCustomFunction,
// error_type_name: ErrorTypeName,
// },
Standard {
error_type_name: ErrorTypeName,
validators: Vec<Validator>,
},
}

impl<Sanitizer, Validator> Guard<Sanitizer, Validator> {
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),
},
}
}
}
Expand Down Expand Up @@ -291,7 +305,9 @@ impl<Sanitizer, Validator> Guard<Sanitizer, Validator> {

pub fn validators(&self) -> Option<&Vec<Validator>> {
match self {
Self::WithValidation { validators, .. } => Some(validators),
Self::WithValidation { validation, .. } => match validation {
Validation::Standard { validators, .. } => Some(validators),
},
Self::WithoutValidation { .. } => None,
}
}
Expand Down
8 changes: 5 additions & 3 deletions nutype_macros/src/common/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -35,8 +35,10 @@ pub fn validate_guard<RawSanitizer, RawValidator, Sanitizer, Validator>(
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,
},
})
}
}
Expand Down
15 changes: 10 additions & 5 deletions nutype_macros/src/float/gen/traits/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -65,11 +65,16 @@ fn gen_generate_valid_inner_value<T: ToTokens>(
}
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,
)
}
}
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions nutype_macros/src/float/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -64,9 +64,11 @@ where
fn has_validation_against_nan<T>(guard: &FloatGuard<T>) -> 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),
},
}
}

Expand Down
56 changes: 31 additions & 25 deletions nutype_macros/src/integer/gen/traits/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -66,31 +66,37 @@ fn guard_to_boundary<T: ToTokens>(
}
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",
));
}
}
}
}
}
Expand Down
13 changes: 10 additions & 3 deletions nutype_macros/src/string/gen/traits/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -110,9 +110,10 @@ fn build_specification(guard: &StringGuard) -> Result<Option<Specification>, 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)?;

Expand Down Expand Up @@ -150,6 +151,12 @@ fn build_specification(guard: &StringGuard) -> Result<Option<Specification>, syn
}
}

fn get_validators(validation: &Validation<StringValidator>) -> &[StringValidator] {
match validation {
Validation::Standard { validators, .. } => validators,
}
}

fn filter_validators(validators: &[StringValidator]) -> Result<Vec<RelevantValidator>, syn::Error> {
validators.iter().map(|v| {
match v {
Expand Down
2 changes: 2 additions & 0 deletions nutype_macros/src/string/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down

0 comments on commit 97d5bad

Please sign in to comment.