diff --git a/core/lib/src/form/validate.rs b/core/lib/src/form/validate.rs index 71a3f001..503a144d 100644 --- a/core/lib/src/form/validate.rs +++ b/core/lib/src/form/validate.rs @@ -33,7 +33,7 @@ //! // By defining another function... //! #[field(validate = omits("password").map_err(pass_help))] //! 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`")))] //! password2: &'r str, //! // 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: /// -/// | type | contains | -/// |-------------------------|----------------------------| -/// | `&str`, `String` | `&str`, `char` | -/// | `Vec` | `T`, `&T` | -/// | `Option` | `I` where `T: Contains` | -/// | [`form::Result<'_, T>`] | `I` where `T: Contains` | +/// | type | contains | +/// |-------------------------|----------------------------------------------------| +/// | `&str`, `String` | `&str`, `char`, `&[char]` `F: FnMut(char) -> bool` | +/// | `Vec` | `T`, `&T` | +/// | `Option` | `I` where `T: Contains` | +/// | [`form::Result<'_, T>`] | `I` where `T: Contains` | /// /// [`form::Result<'_, T>`]: crate::form::Result pub trait Contains { @@ -429,12 +429,32 @@ macro_rules! impl_contains { }; } +fn coerce(slice: &[T; N]) -> &[T] { + &slice[..] +} + impl_contains!([] str [contains] &str [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] 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 [contains] &T [via] [T]); +impl bool> Contains for str { + fn contains(&self, f: F) -> bool { + ::contains(self, f) + } +} + +impl bool> Contains for String { + fn contains(&self, f: F) -> bool { + ::contains(self, f) + } +} + impl Contains for Vec { fn contains(&self, item: T) -> bool { <[T]>::contains(self, &item) @@ -461,8 +481,9 @@ impl + ?Sized> Contains for &T { /// Contains validator: succeeds when a value contains `item`. /// -/// The value must implement [`Contains`](Contains) where `I` is the type of -/// the `item`. See [`Contains`] for supported types and items. +/// This is the dual of [`omits()`]. The value must implement +/// [`Contains`](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: /// @@ -470,6 +491,8 @@ impl + ?Sized> Contains for &T { /// value is equal to an invalid value /// ``` /// +/// If the collection is empty, this validator fails. +/// /// # Example /// /// ```rust @@ -485,8 +508,10 @@ impl + ?Sized> Contains for &T { /// #[field(validate = contains(&self.best_pet))] /// pets: Vec, /// #[field(validate = contains('/'))] +/// #[field(validate = contains(&['/', ':']))] /// license: &'r str, /// #[field(validate = contains("@rust-lang.org"))] +/// #[field(validate = contains(|c: char| c.to_ascii_lowercase() == 's'))] /// 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 /// error message. /// -/// The is identical to [`contains()`] except that `item` must be `Debug + Copy` -/// and the error message is as follows, where `$item` is the [`Debug`] -/// representation of `item`: +/// This is the dual of [`dbg_omits()`]. The is identical to [`contains()`] +/// except that `item` must be `Debug + Copy` and the error message is as +/// follows, where `$item` is the [`Debug`] representation of `item`: /// /// ```text /// values must contains $item /// ``` /// +/// If the collection is empty, this validator fails. +/// /// # Example /// /// ```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`. /// error message. /// -/// The value must implement [`Contains`](Contains) where `I` is the type of -/// the `item`. See [`Contains`] for supported types and items. +/// This is the dual of [`contains()`]. The value must implement +/// [`Contains`](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: /// @@ -549,6 +577,8 @@ pub fn dbg_contains<'v, V, I>(value: V, item: I) -> Result<'v, ()> /// value contains a disallowed item /// ``` /// +/// If the collection is empty, this validator succeeds. +/// /// # Example /// /// ```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 /// message. /// -/// The is identical to [`omits()`] except that `item` must be `Debug + Copy` -/// and the error message is as follows, where `$item` is the [`Debug`] -/// representation of `item`: +/// This is the dual of [`dbg_contains()`]. The is identical to [`omits()`] +/// except that `item` must be `Debug + Copy` and the error message is as +/// follows, where `$item` is the [`Debug`] representation of `item`: /// /// ```text /// value cannot contain $item /// ``` /// +/// If the collection is empty, this validator succeeds. +/// /// # Example /// /// ```rust