-
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
Trait validation #225
Conversation
validator/src/validation/length.rs
Outdated
@@ -32,11 +34,33 @@ pub fn validate_length<T: HasLen>( | |||
true | |||
} | |||
|
|||
pub trait ValidateLenght: HasLen { |
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.
It seems like if the user wants to implement ValidateLength
on their own type, they'd need to also implement HaLen
?
Might it be simpler if HasLen
is not involved?
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.
Typo on the name and it shouldn't use HasLen
at all. Then we can just create a macro to generate all the impls we want for each type. With this trait, HasLen doesn't exist anymore
validator/src/validation/length.rs
Outdated
@@ -32,11 +34,33 @@ pub fn validate_length<T: HasLen>( | |||
true | |||
} | |||
|
|||
pub trait ValidateLenght: HasLen { |
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.
Typo on the name and it shouldn't use HasLen
at all. Then we can just create a macro to generate all the impls we want for each type. With this trait, HasLen doesn't exist anymore
Okay I changed the trait and updated the implementations. The length extraction has to be done inside the |
I tried making a macro with
from something like this
|
I have implemented all the impls that had the |
validator/src/validation/length.rs
Outdated
|
||
impl ValidateLength for String { | ||
fn validate_length(&self, min: Option<u64>, max: Option<u64>, equal: Option<u64>) -> bool { | ||
validate_length_for_trait(self.chars().count() as u64, min, max, equal) |
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.
What made you decide to go with self.chars().count()
instead of self.len()
?
And why use u64 everywhere instead of usize
?
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 used self.chars().count()
because the HasLen
trait used them too and I didn't really think about it. The same is for u64
instead of usize
. The validate_length
function used Option<u64>
. I can refactor the trait to use self.len()
and usize
if it makes any difference.
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.
Strings should use self.chars().count()
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.
@Keats interesting, what is the advantage of that over .len()
?
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.
fn main() {
let txt = "日本語";
println!("len {:?} vs chars {:?}", txt.len(), txt.chars().count());
}
will print
len 9 vs chars 3
In this case no one reasonable will think of len as number of bytes used (.len()
) vs number of characters, which is what people think of when they think of a len for a string.
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.
Wow very interesting! Makes sense to use chars count then
Now I'm unsure what path to go. Do we let users implement the validation logic by themselves like so
This fees like cumebrsome and I would prefer if the user just has to implement a
And maybe leave the first example for the |
I don't see what this |
It's just there so the user can specify how to get the length value from a custom type. This is then used in the Now that I think about it, it's the same as it was before with the |
How about this, the trait |
I think that looks good |
validator/src/validation/email.rs
Outdated
true | ||
} | ||
|
||
fn to_email_string(&self) -> String; |
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.
That implies allocation, it should return a &str
instead
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.
Returning a &str
is impossible if I want to return a formatted string for example
fn to_email_string(&self) -> &str {
format!("{}@{}", self.user_part, self.domain_part).as_str()
}
How about returning Cow?
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.
Cow is fine then
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 comment
The 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?
pub use validation::ip::{validate_ip, validate_ip_v4, validate_ip_v6}; | ||
pub use validation::length::validate_length; | ||
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; | ||
#[cfg(feature = "phone")] | ||
pub use validation::phone::validate_phone; |
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?
What's the status on this? Is there anything that can be picked up here? |
Just need some time to take that PR in and re-do the derive impl. I should have some more free time from next week on and could use a little break from Zola. |
Just a friendly ping @Keats :) We could also try to assist as we use this lib quite a bit. |
Yes that would be great. I started to have a look at the derive crate and it seems nicer to use than 7 years ago. It also made me realise we were not handling the rename_all of serde afaik so that rename feature kinda sucked but no one complained? Maybe it's not super useful in the end. The library itself should be that PR but I don't know whether we should do it in 2 phases (validation as trait -> derive rewrite later) or try to do it in one go. I've created a |
* implemented validation trait for length * converted identation to spaces * changed the trait to not require HasLen * added macro for generating impls * implemented ValidateLength for some types * using trait validation instead of the function * added cfg for indexmap import * changed trait to require length * Revert "changed trait to require length" This reverts commit a77bdc9. * moved validation logic inside ValidateLength trait * added trait validation for required * added email trait validation * fixed trait validation for email * added range trait validation * fixed range trait * added url trait validation --------- Co-authored-by: Tilen Pintarič <tilen.pintaric@aviko.si>
* implemented validation trait for length * converted identation to spaces * changed the trait to not require HasLen * added macro for generating impls * implemented ValidateLength for some types * using trait validation instead of the function * added cfg for indexmap import * changed trait to require length * Revert "changed trait to require length" This reverts commit a77bdc9. * moved validation logic inside ValidateLength trait * added trait validation for required * added email trait validation * fixed trait validation for email * added range trait validation * fixed range trait * added url trait validation --------- Co-authored-by: Tilen Pintarič <tilen.pintaric@aviko.si>
I've implemented trait validation as mentioned in #205.
For now I've just implemented it for the
length
validation just to see if I'm on the right track. I've also copied the tests just to be sure it works.Now if you want length validation for a custom type you just have to write an
impl
block for it like