Allow more types in 'contains' field validator.

The validator can now validate string contents with:

    * '&[char]'
    * 'F: FnMut(char) -> bool'
This commit is contained in:
Sergio Benitez 2021-06-01 11:30:34 -07:00
parent cf5ccc4b2e
commit 8214df4a56
1 changed files with 49 additions and 17 deletions

View File

@ -33,7 +33,7 @@
//! // By defining another function... //! // By defining another function...
//! #[field(validate = omits("password").map_err(pass_help))] //! #[field(validate = omits("password").map_err(pass_help))]
//! password: &'r str, //! password: &'r str,
//! // or inline using the `msg` helper. //! // or inline using the `msg` helper. `or_else` inverts the validator
//! #[field(validate = omits("password").or_else(msg!("please omit `password`")))] //! #[field(validate = omits("password").or_else(msg!("please omit `password`")))]
//! password2: &'r str, //! password2: &'r str,
//! // You can even refer to the field in the message... //! // You can even refer to the field in the message...
@ -402,12 +402,12 @@ pub fn len<'v, V, L, R>(value: V, range: R) -> Result<'v, ()>
/// ///
/// At present, these are: /// At present, these are:
/// ///
/// | type | contains | /// | type | contains |
/// |-------------------------|----------------------------| /// |-------------------------|----------------------------------------------------|
/// | `&str`, `String` | `&str`, `char` | /// | `&str`, `String` | `&str`, `char`, `&[char]` `F: FnMut(char) -> bool` |
/// | `Vec<T>` | `T`, `&T` | /// | `Vec<T>` | `T`, `&T` |
/// | `Option<T>` | `I` where `T: Contains<I>` | /// | `Option<T>` | `I` where `T: Contains<I>` |
/// | [`form::Result<'_, T>`] | `I` where `T: Contains<I>` | /// | [`form::Result<'_, T>`] | `I` where `T: Contains<I>` |
/// ///
/// [`form::Result<'_, T>`]: crate::form::Result /// [`form::Result<'_, T>`]: crate::form::Result
pub trait Contains<I> { pub trait Contains<I> {
@ -429,12 +429,32 @@ macro_rules! impl_contains {
}; };
} }
fn coerce<T, const N: usize>(slice: &[T; N]) -> &[T] {
&slice[..]
}
impl_contains!([] str [contains] &str [via] str); impl_contains!([] str [contains] &str [via] str);
impl_contains!([] str [contains] char [via] str); impl_contains!([] str [contains] char [via] str);
impl_contains!([] str [contains] &[char] [via] str);
impl_contains!([const N: usize] str [contains] &[char; N] [via] str [with] coerce);
impl_contains!([] String [contains] &str [via] str); impl_contains!([] String [contains] &str [via] str);
impl_contains!([] String [contains] char [via] str); impl_contains!([] String [contains] char [via] str);
impl_contains!([] String [contains] &[char] [via] str);
impl_contains!([const N: usize] String [contains] &[char; N] [via] str [with] coerce);
impl_contains!([T: PartialEq] Vec<T> [contains] &T [via] [T]); impl_contains!([T: PartialEq] Vec<T> [contains] &T [via] [T]);
impl<F: FnMut(char) -> bool> Contains<F> for str {
fn contains(&self, f: F) -> bool {
<str>::contains(self, f)
}
}
impl<F: FnMut(char) -> bool> Contains<F> for String {
fn contains(&self, f: F) -> bool {
<str>::contains(self, f)
}
}
impl<T: PartialEq> Contains<T> for Vec<T> { impl<T: PartialEq> Contains<T> for Vec<T> {
fn contains(&self, item: T) -> bool { fn contains(&self, item: T) -> bool {
<[T]>::contains(self, &item) <[T]>::contains(self, &item)
@ -461,8 +481,9 @@ impl<I, T: Contains<I> + ?Sized> Contains<I> for &T {
/// Contains validator: succeeds when a value contains `item`. /// Contains validator: succeeds when a value contains `item`.
/// ///
/// The value must implement [`Contains<I>`](Contains) where `I` is the type of /// This is the dual of [`omits()`]. The value must implement
/// the `item`. See [`Contains`] for supported types and items. /// [`Contains<I>`](Contains) where `I` is the type of the `item`. See
/// [`Contains`] for supported types and items.
/// ///
/// On failure, returns a validation error with the following message: /// On failure, returns a validation error with the following message:
/// ///
@ -470,6 +491,8 @@ impl<I, T: Contains<I> + ?Sized> Contains<I> for &T {
/// value is equal to an invalid value /// value is equal to an invalid value
/// ``` /// ```
/// ///
/// If the collection is empty, this validator fails.
///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
@ -485,8 +508,10 @@ impl<I, T: Contains<I> + ?Sized> Contains<I> for &T {
/// #[field(validate = contains(&self.best_pet))] /// #[field(validate = contains(&self.best_pet))]
/// pets: Vec<Pet>, /// pets: Vec<Pet>,
/// #[field(validate = contains('/'))] /// #[field(validate = contains('/'))]
/// #[field(validate = contains(&['/', ':']))]
/// license: &'r str, /// license: &'r str,
/// #[field(validate = contains("@rust-lang.org"))] /// #[field(validate = contains("@rust-lang.org"))]
/// #[field(validate = contains(|c: char| c.to_ascii_lowercase() == 's'))]
/// rust_lang_email: &'r str, /// rust_lang_email: &'r str,
/// } /// }
/// ``` /// ```
@ -503,14 +528,16 @@ pub fn contains<'v, V, I>(value: V, item: I) -> Result<'v, ()>
/// Debug contains validator: like [`contains()`] but mentions `item` in the /// Debug contains validator: like [`contains()`] but mentions `item` in the
/// error message. /// error message.
/// ///
/// The is identical to [`contains()`] except that `item` must be `Debug + Copy` /// This is the dual of [`dbg_omits()`]. The is identical to [`contains()`]
/// and the error message is as follows, where `$item` is the [`Debug`] /// except that `item` must be `Debug + Copy` and the error message is as
/// representation of `item`: /// follows, where `$item` is the [`Debug`] representation of `item`:
/// ///
/// ```text /// ```text
/// values must contains $item /// values must contains $item
/// ``` /// ```
/// ///
/// If the collection is empty, this validator fails.
///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
@ -540,8 +567,9 @@ pub fn dbg_contains<'v, V, I>(value: V, item: I) -> Result<'v, ()>
/// Omits validator: succeeds when a value _does not_ contains `item`. /// Omits validator: succeeds when a value _does not_ contains `item`.
/// error message. /// error message.
/// ///
/// The value must implement [`Contains<I>`](Contains) where `I` is the type of /// This is the dual of [`contains()`]. The value must implement
/// the `item`. See [`Contains`] for supported types and items. /// [`Contains<I>`](Contains) where `I` is the type of the `item`. See
/// [`Contains`] for supported types and items.
/// ///
/// On failure, returns a validation error with the following message: /// On failure, returns a validation error with the following message:
/// ///
@ -549,6 +577,8 @@ pub fn dbg_contains<'v, V, I>(value: V, item: I) -> Result<'v, ()>
/// value contains a disallowed item /// value contains a disallowed item
/// ``` /// ```
/// ///
/// If the collection is empty, this validator succeeds.
///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
@ -580,14 +610,16 @@ pub fn omits<'v, V, I>(value: V, item: I) -> Result<'v, ()>
/// Debug omits validator: like [`omits()`] but mentions `item` in the error /// Debug omits validator: like [`omits()`] but mentions `item` in the error
/// message. /// message.
/// ///
/// The is identical to [`omits()`] except that `item` must be `Debug + Copy` /// This is the dual of [`dbg_contains()`]. The is identical to [`omits()`]
/// and the error message is as follows, where `$item` is the [`Debug`] /// except that `item` must be `Debug + Copy` and the error message is as
/// representation of `item`: /// follows, where `$item` is the [`Debug`] representation of `item`:
/// ///
/// ```text /// ```text
/// value cannot contain $item /// value cannot contain $item
/// ``` /// ```
/// ///
/// If the collection is empty, this validator succeeds.
///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust