-
Notifications
You must be signed in to change notification settings - Fork 144
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
Trait validation #225
Merged
Merged
Trait validation #225
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
babd938
implemented validation trait for length
02bdd69
converted identation to spaces
5836898
changed the trait to not require HasLen
bd9e89f
added macro for generating impls
8bd86e8
implemented ValidateLength for some types
de20a94
using trait validation instead of the function
ee04dd0
added cfg for indexmap import
a77bdc9
changed trait to require length
pintariching 0790ded
Revert "changed trait to require length"
3277682
moved validation logic inside ValidateLength trait
66380b6
added trait validation for required
34c12ee
added email trait validation
ba0e745
fixed trait validation for email
090abc5
added range trait validation
63559f8
fixed range trait
9aeb298
added url trait validation
77520dc
Merge branch 'master' into trait-validation
pintariching File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,164 @@ | ||
use crate::traits::HasLen; | ||
use std::{borrow::Cow, collections::{HashMap, HashSet, BTreeMap, BTreeSet}}; | ||
|
||
#[cfg(feature = "indexmap")] | ||
use indexmap::{IndexMap, IndexSet}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thoughts on letting crates handle validator support themselves like they do for serde? |
||
|
||
/// Validates the length of the value given. | ||
/// If the validator has `equal` set, it will ignore any `min` and `max` value. | ||
/// | ||
/// If you apply it on String, don't forget that the length can be different | ||
/// from the number of visual characters for Unicode | ||
#[must_use] | ||
pub fn validate_length<T: HasLen>( | ||
pub fn validate_length<T: ValidateLength>( | ||
value: T, | ||
min: Option<u64>, | ||
max: Option<u64>, | ||
equal: Option<u64>, | ||
) -> bool { | ||
let val_length = value.length(); | ||
|
||
if let Some(eq) = equal { | ||
return val_length == eq; | ||
} else { | ||
if let Some(m) = min { | ||
if val_length < m { | ||
return false; | ||
} | ||
} | ||
if let Some(m) = max { | ||
if val_length > m { | ||
return false; | ||
} | ||
} | ||
} | ||
value.validate_length(min, max, equal) | ||
} | ||
|
||
pub trait ValidateLength { | ||
fn validate_length(&self, min: Option<u64>, max: Option<u64>, equal: Option<u64>) -> bool { | ||
let length = self.length(); | ||
|
||
if let Some(eq) = equal { | ||
return length == eq; | ||
} else { | ||
if let Some(m) = min { | ||
if length < m { | ||
return false; | ||
} | ||
} | ||
if let Some(m) = max { | ||
if length > m { | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
true | ||
} | ||
|
||
fn length(&self) -> u64; | ||
} | ||
|
||
impl ValidateLength for String { | ||
fn length(&self) -> u64 { | ||
self.chars().count() as u64 | ||
} | ||
} | ||
|
||
impl<'a> ValidateLength for &'a String { | ||
fn length(&self) -> u64 { | ||
self.chars().count() as u64 | ||
} | ||
} | ||
|
||
impl<'a> ValidateLength for &'a str { | ||
fn length(&self) -> u64 { | ||
self.chars().count() as u64 | ||
} | ||
} | ||
|
||
impl<'a> ValidateLength for Cow<'a, str> { | ||
fn length(&self) -> u64 { | ||
self.chars().count() as u64 | ||
} | ||
} | ||
|
||
impl<T> ValidateLength for Vec<T> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
impl<'a, T> ValidateLength for &'a Vec<T> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
impl<T> ValidateLength for &[T] { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
impl<T, const N: usize> ValidateLength for [T; N] { | ||
fn length(&self) -> u64 { | ||
N as u64 | ||
} | ||
} | ||
|
||
impl<T, const N: usize> ValidateLength for &[T; N] { | ||
fn length(&self) -> u64 { | ||
N as u64 | ||
} | ||
} | ||
|
||
impl<'a, K, V, S> ValidateLength for &'a HashMap<K, V, S> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
impl<K, V, S> ValidateLength for HashMap<K, V, S> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
impl<'a, T, S> ValidateLength for &'a HashSet<T, S> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
impl<'a, K, V> ValidateLength for &'a BTreeMap<K, V> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
true | ||
impl<'a, T> ValidateLength for &'a BTreeSet<T> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
impl<T> ValidateLength for BTreeSet<T> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
#[cfg(feature = "indexmap")] | ||
impl<'a, K, V> ValidateLength for &'a IndexMap<K, V> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
#[cfg(feature = "indexmap")] | ||
impl<'a, T> ValidateLength for &'a IndexSet<T> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
#[cfg(feature = "indexmap")] | ||
impl<T> ValidateLength for IndexSet<T> { | ||
fn length(&self) -> u64 { | ||
self.len() as u64 | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::borrow::Cow; | ||
|
||
use super::validate_length; | ||
use crate::{validate_length, validation::length::ValidateLength}; | ||
|
||
#[test] | ||
fn test_validate_length_equal_overrides_min_max() { | ||
|
@@ -76,4 +198,44 @@ mod tests { | |
fn test_validate_length_unicode_chars() { | ||
assert!(validate_length("日本", None, None, Some(2))); | ||
} | ||
|
||
|
||
#[test] | ||
fn test_validate_length_trait_equal_overrides_min_max() { | ||
assert!(String::from("hello").validate_length(Some(1), Some(2), Some(5))); | ||
} | ||
|
||
#[test] | ||
fn test_validate_length_trait_string_min_max() { | ||
assert!(String::from("hello").validate_length(Some(1), Some(10), None)); | ||
} | ||
|
||
#[test] | ||
fn test_validate_length_trait_string_min_only() { | ||
assert!(!String::from("hello").validate_length(Some(10), None, None)); | ||
} | ||
|
||
#[test] | ||
fn test_validate_length_trait_string_max_only() { | ||
assert!(!String::from("hello").validate_length(None, Some(1), None)); | ||
} | ||
|
||
#[test] | ||
fn test_validate_length_trait_cow() { | ||
let test: Cow<'static, str> = "hello".into(); | ||
assert!(test.validate_length(None, None, Some(5))); | ||
|
||
let test: Cow<'static, str> = String::from("hello").into(); | ||
assert!(test.validate_length(None, None, Some(5))); | ||
} | ||
|
||
#[test] | ||
fn test_validate_length_trait_vec() { | ||
assert!(vec![1, 2, 3].validate_length(None, None, Some(3))); | ||
} | ||
|
||
#[test] | ||
fn test_validate_length_trait_unicode_chars() { | ||
assert!(String::from("日本").validate_length(None, None, Some(2))); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm tempted to remove that one from validator, it's currently too generic to be easily usable and can easily be added manually if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe leaving an example on how to add it with a custom validator after removing it would be a good idea?