Skip to content

Commit

Permalink
Switch non-control-character validator to a trait (#257)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyrias authored and Keats committed Mar 4, 2024
1 parent 22d57e4 commit 0271e95
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 23 deletions.
4 changes: 3 additions & 1 deletion validator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ pub use validation::ip::{validate_ip, validate_ip_v4, validate_ip_v6};
pub use validation::length::{validate_length, ValidateLength};
pub use validation::must_match::validate_must_match;
#[cfg(feature = "unic")]
pub use validation::non_control_character::validate_non_control_character;
pub use validation::non_control_character::{
validate_non_control_character, ValidateNonControlCharacter,
};
pub use validation::range::{validate_range, ValidateRange};

pub use validation::required::{validate_required, ValidateRequired};
Expand Down
23 changes: 17 additions & 6 deletions validator/src/validation/non_control_character.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
use std::borrow::Cow;
use unic_ucd_common::control;

#[must_use]
pub fn validate_non_control_character<'a, T>(alphabetic: T) -> bool
where
T: Into<Cow<'a, str>> + Clone,
{
alphabetic.into().chars().all(|code| !control::is_control(code))
pub fn validate_non_control_character<T: ValidateNonControlCharacter>(val: T) -> bool {
val.validate_non_control_character()
}

pub trait ValidateNonControlCharacter {
#[must_use]
fn validate_non_control_character(&self) -> bool {
self.to_non_control_character_iterator().all(|code| !control::is_control(code))
}

fn to_non_control_character_iterator(&self) -> Box<dyn Iterator<Item = char> + '_>;
}

impl<T: AsRef<str>> ValidateNonControlCharacter for T {
fn to_non_control_character_iterator(&self) -> Box<dyn Iterator<Item = char> + '_> {
Box::new(self.as_ref().chars())
}
}

#[cfg(test)]
Expand Down
10 changes: 0 additions & 10 deletions validator_derive/src/asserts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,6 @@ pub static NUMBER_TYPES: [&str; 38] = [
"Option<Option<f64>>",
];

pub fn assert_string_type(name: &str, type_name: &str, field_type: &syn::Type) {
if !type_name.contains("String") && !type_name.contains("str") {
abort!(
field_type.span(),
"`{}` validator can only be used on String, &str, Cow<'_,str> or an Option of those",
name
);
}
}

pub fn assert_type_matches(
field_name: String,
field_type: &str,
Expand Down
7 changes: 1 addition & 6 deletions validator_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use quote::ToTokens;
use quote::{quote, quote_spanned};
use syn::{parse_quote, spanned::Spanned, GenericParam, Lifetime, LifetimeDef, Type};

use asserts::{assert_has_len, assert_has_range, assert_string_type, assert_type_matches};
use asserts::{assert_has_len, assert_has_range, assert_type_matches};
use lit::*;
use quoting::{quote_schema_validations, quote_validator, FieldQuoter};
use validation::*;
Expand Down Expand Up @@ -420,11 +420,6 @@ fn find_validators_for_field(
}
#[cfg(feature = "unic")]
"non_control_character" => {
assert_string_type(
"non_control_character",
field_type,
&field.ty,
);
validators.push(FieldValidation::new(
Validator::NonControlCharacter,
));
Expand Down
28 changes: 28 additions & 0 deletions validator_derive_tests/tests/non_control.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use serde::Serialize;
use validator::Validate;

#[test]
Expand Down Expand Up @@ -65,3 +66,30 @@ fn can_specify_message_for_non_control_character() {
assert_eq!(errs["val"].len(), 1);
assert_eq!(errs["val"][0].clone().message.unwrap(), "oops");
}

#[test]
fn can_validate_custom_impl_for_non_control_character() {
#[derive(Debug, Serialize)]
struct CustomNonControlCharacter {
char: char,
}

#[derive(Debug, Validate)]
struct TestStruct {
#[validate(non_control_character)]
val: CustomNonControlCharacter,
}

impl validator::ValidateNonControlCharacter for &CustomNonControlCharacter {
fn to_non_control_character_iterator(&self) -> Box<dyn Iterator<Item = char> + '_> {
Box::new(std::iter::once(self.char))
}
}

let valid = TestStruct { val: CustomNonControlCharacter { char: 'a' } };

let invalid = TestStruct { val: CustomNonControlCharacter { char: '\u{000c}' } };

assert!(valid.validate().is_ok());
assert!(invalid.validate().is_err());
}

0 comments on commit 0271e95

Please sign in to comment.