Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Validation enum #167

Merged
merged 2 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading