//! Form field validation routines.
//!
//! Each function in this module can be used as the target of the
//! `field(validate)` field attribute of the `FromForm` derive.
//!
//! ```rust
//! use rocket::form::FromForm;
//!
//! #[derive(FromForm)]
//! struct MyForm<'r> {
//! #[field(validate = range(2..10))]
//! id: usize,
//! #[field(validate = omits("password"))]
//! password: &'r str,
//! }
//! ```
//!
//! The `validate` parameter takes any expression that returns a
//! [`form::Result<()>`](crate::form::Result). If the expression is a function
//! call, a reference to the field is inserted as the first parameter. Thus,
//! functions calls to `validate` must take a reference to _some_ type,
//! typically a generic with some bounds, as their first argument.
//!
//! ## Custom Error Messages
//!
//! To set a custom error messages, it is useful to chain results:
//!
//! ```rust
//! use rocket::form::{Errors, Error, FromForm};
//!
//! #[derive(FromForm)]
//! struct MyForm<'r> {
//! // By defining another function...
//! #[field(validate = omits("password").map_err(pass_help))]
//! password: &'r str,
//! // 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...
//! #[field(validate = range(1..).or_else(msg!("`{}` < 1", self.n)))]
//! n: isize,
//! // ..or other fields!
//! #[field(validate = range(..self.n).or_else(msg!("`{}` > `{}`", self.z, self.n)))]
//! z: isize,
//! }
//!
//! fn pass_help<'a>(errors: Errors<'_>) -> Errors<'a> {
//! Error::validation("passwords can't contain the text \"password\"").into()
//! }
//! ```
//!
//! ## Custom Validation
//!
//! Custom validation routines can be defined as regular functions. Consider a
//! routine that tries to validate a credit card number:
//!
//! ```rust
//! extern crate time;
//!
//! use rocket::form::{self, FromForm, Error};
//!
//! #[derive(FromForm)]
//! struct CreditCard {
//! #[field(validate = luhn(self.cvv, &self.expiration))]
//! number: u64,
//! cvv: u16,
//! expiration: time::Date,
//! }
//!
//! // Implementation of Luhn validator.
//! fn luhn<'v>(number: &u64, cvv: u16, exp: &time::Date) -> form::Result<'v, ()> {
//! # let valid = false;
//! if !valid {
//! Err(Error::validation("invalid credit card number"))?;
//! }
//!
//! Ok(())
//! }
//! ```
use Cow;
use TryInto;
use ;
use Debug;
use crate ByteUnit;
use ContentType;
use crate::;
crate export!
/// Equality validator: succeeds exactly when `a` == `b`, using [`PartialEq`].
///
/// On failure, returns a validation error with the following message:
///
/// ```text
/// value does not match expected value
/// ```
///
/// # Example
///
/// ```rust
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(FromFormField, PartialEq)]
/// enum Kind {
/// Car,
/// Truck
/// }
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// #[field(validate = eq("Bob Marley"))]
/// name: &'r str,
/// #[field(validate = eq(Kind::Car))]
/// vehicle: Kind,
/// #[field(validate = eq(&[5, 7, 8]))]
/// numbers: Vec<usize>,
/// }
/// ```
/// Debug equality validator: like [`eq()`] but mentions `b` in the error
/// message.
///
/// The is identical to [`eq()`] except that `b` must be `Debug` and the error
/// message is as follows, where `$b` is the [`Debug`] representation of `b`:
///
/// ```text
/// value must be $b
/// ```
///
/// # Example
///
/// ```rust
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(PartialEq, Debug, Clone, Copy, FromFormField)]
/// enum Pet { Cat, Dog }
///
/// #[derive(FromForm)]
/// struct Foo {
/// number: usize,
/// #[field(validate = dbg_eq(self.number))]
/// confirm_num: usize,
/// #[field(validate = dbg_eq(Pet::Dog))]
/// best_pet: Pet,
/// }
/// ```
/// Negative equality validator: succeeds exactly when `a` != `b`, using
/// [`PartialEq`].
///
/// On failure, returns a validation error with the following message:
///
/// ```text
/// value is equal to an invalid value
/// ```
///
/// # Example
///
/// ```rust
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(FromFormField, PartialEq)]
/// enum Kind {
/// Car,
/// Truck
/// }
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// #[field(validate = neq("Bob Marley"))]
/// name: &'r str,
/// #[field(validate = neq(Kind::Car))]
/// vehicle: Kind,
/// #[field(validate = neq(&[5, 7, 8]))]
/// numbers: Vec<usize>,
/// }
/// ```
/// Types for values that have a length.
///
/// At present, these are:
///
/// | type | length description |
/// |-----------------------------------|--------------------------------------|
/// | `&str`, `String` | length in bytes |
/// | `Vec<T>` | number of elements in the vector |
/// | `HashMap<K, V>`, `BTreeMap<K, V>` | number of key/value pairs in the map |
/// | [`TempFile`] | length of the file in bytes |
/// | `Option<T>` where `T: Len` | length of `T` or 0 if `None` |
/// | [`form::Result<'_, T>`] | length of `T` or 0 if `Err` |
///
/// [`form::Result<'_, T>`]: crate::form::Result
impl_len!;
impl_len!;
impl_len!;
impl_len!;
impl_len!;
impl_len!;
/// Length validator: succeeds when the length of a value is within a `range`.
///
/// The value must implement [`Len`]. On failure, returns an [`InvalidLength`]
/// error. See [`Len`] for supported types and how their length is computed.
///
/// [`InvalidLength`]: crate::form::error::ErrorKind::InvalidLength
///
/// # Data Limits
///
/// All form types are constrained by a data limit. As such, the `len()`
/// validator should be used only when a data limit is insufficiently specific.
/// For example, prefer to use data [`Limits`](crate::data::Limits) to validate
/// the length of files as not doing so will result in writing more data to disk
/// than necessary.
///
/// # Example
///
/// ```rust
/// use rocket::http::ContentType;
/// use rocket::form::{FromForm, FromFormField};
/// use rocket::data::ToByteUnit;
/// use rocket::fs::TempFile;
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// #[field(validate = len(5..20))]
/// name: &'r str,
/// #[field(validate = len(..=200))]
/// maybe_name: Option<&'r str>,
/// #[field(validate = len(..=2.mebibytes()))]
/// #[field(validate = ext(ContentType::Plain))]
/// file: TempFile<'r>,
/// }
/// ```
/// Types for values that contain items.
///
/// At present, these are:
///
/// | type | contains |
/// |-------------------------|----------------------------------------------------|
/// | `&str`, `String` | `&str`, `char`, `&[char]` `F: FnMut(char) -> bool` |
/// | `Vec<T>` | `T`, `&T` |
/// | `Option<T>` | `I` where `T: Contains<I>` |
/// | [`form::Result<'_, T>`] | `I` where `T: Contains<I>` |
///
/// [`form::Result<'_, T>`]: crate::form::Result
impl_contains!;
impl_contains!;
impl_contains!;
impl_contains!;
impl_contains!;
impl_contains!;
impl_contains!;
impl_contains!;
impl_contains!;
/// Contains validator: succeeds when a value contains `item`.
///
/// This is the dual of [`omits()`]. The value must implement
/// [`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:
///
/// ```text
/// value is equal to an invalid value
/// ```
///
/// If the collection is empty, this validator fails.
///
/// # Example
///
/// ```rust
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(PartialEq, FromFormField)]
/// enum Pet { Cat, Dog }
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// best_pet: Pet,
/// #[field(validate = contains(Pet::Cat))]
/// #[field(validate = contains(&self.best_pet))]
/// pets: Vec<Pet>,
/// #[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,
/// }
/// ```
/// Debug contains validator: like [`contains()`] but mentions `item` in the
/// error message.
///
/// 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
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(PartialEq, Debug, Clone, Copy, FromFormField)]
/// enum Pet { Cat, Dog }
///
/// #[derive(FromForm)]
/// struct Foo {
/// best_pet: Pet,
/// #[field(validate = dbg_contains(Pet::Dog))]
/// #[field(validate = dbg_contains(&self.best_pet))]
/// pets: Vec<Pet>,
/// }
/// ```
/// Omits validator: succeeds when a value _does not_ contains `item`.
/// error message.
///
/// This is the dual of [`contains()`]. The value must implement
/// [`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:
///
/// ```text
/// value contains a disallowed item
/// ```
///
/// If the collection is empty, this validator succeeds.
///
/// # Example
///
/// ```rust
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(PartialEq, FromFormField)]
/// enum Pet { Cat, Dog }
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// #[field(validate = omits(Pet::Cat))]
/// pets: Vec<Pet>,
/// #[field(validate = omits('@'))]
/// not_email: &'r str,
/// #[field(validate = omits("@gmail.com"))]
/// non_gmail_email: &'r str,
/// }
/// ```
/// Debug omits validator: like [`omits()`] but mentions `item` in the error
/// message.
///
/// 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
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(PartialEq, Debug, Clone, Copy, FromFormField)]
/// enum Pet { Cat, Dog }
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// #[field(validate = dbg_omits(Pet::Cat))]
/// pets: Vec<Pet>,
/// #[field(validate = dbg_omits('@'))]
/// not_email: &'r str,
/// #[field(validate = dbg_omits("@gmail.com"))]
/// non_gmail_email: &'r str,
/// }
/// ```
/// Integer range validator: succeeds when an integer value is within a range.
///
/// The value must be an integer type that implement `TryInto<isize> + Copy`. On
/// failure, returns an [`OutOfRange`] error.
///
/// [`OutOfRange`]: crate::form::error::ErrorKind::OutOfRange
///
/// # Example
///
/// ```rust
/// use rocket::form::FromForm;
///
/// #[derive(FromForm)]
/// struct Foo {
/// #[field(validate = range(0..))]
/// non_negative: isize,
/// #[field(validate = range(18..=130))]
/// maybe_adult: u8,
/// }
/// ```
/// Contains one of validator: succeeds when a value contains at least one item
/// in an `items` iterator.
///
/// The value must implement [`Contains<I>`](Contains) where `I` is the type of
/// the `item`. The iterator must be [`Clone`]. See [`Contains`] for supported
/// types and items. The item must be [`Debug`].
///
/// On failure, returns a [`InvalidChoice`] error with the debug representation
/// of each item in `items`.
///
/// [`InvalidChoice`]: crate::form::error::ErrorKind::InvalidChoice
///
/// # Example
///
/// ```rust
/// use rocket::form::FromForm;
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// #[field(validate = one_of(&[3, 5, 7]))]
/// single_digit_primes: Vec<u8>,
/// #[field(validate = one_of(" \t\n".chars()))]
/// has_space_char: &'r str,
/// #[field(validate = one_of(" \t\n".chars()).and_then(msg!("no spaces")))]
/// no_space: &'r str,
/// }
/// ```
/// File type validator: succeeds when a [`TempFile`] has the Content-Type
/// `content_type`.
///
/// On failure, returns a validation error with one of the following messages:
///
/// ```text
/// // the file has an incorrect extension
/// file type was .$file_ext but must be $type
///
/// // the file does not have an extension
/// file type must be $type
/// ```
///
/// # Example
///
/// ```rust
/// use rocket::form::FromForm;
/// use rocket::data::ToByteUnit;
/// use rocket::http::ContentType;
/// use rocket::fs::TempFile;
///
/// #[derive(FromForm)]
/// struct Foo<'r> {
/// #[field(validate = ext(ContentType::PDF))]
/// #[field(validate = len(..1.mebibytes()))]
/// document: TempFile<'r>,
/// }
/// ```
/// With validator: succeeds when an arbitrary function or closure does.
///
/// This is the most generic validator and, for readability, should only be used
/// when a more case-specific option does not exist. It succeeds excactly when
/// `f` returns `true` and fails otherwise.
///
/// On failure, returns a validation error with the message `msg`.
///
/// # Example
///
/// ```rust
/// use rocket::form::{FromForm, FromFormField};
///
/// #[derive(PartialEq, FromFormField)]
/// enum Pet { Cat, Dog }
///
/// #[derive(FromForm)]
/// struct Foo {
/// // These are equivalent. Prefer the former.
/// #[field(validate = contains(Pet::Dog))]
/// #[field(validate = with(|pets| pets.iter().any(|p| *p == Pet::Dog), "missing dog"))]
/// pets: Vec<Pet>,
/// // These are equivalent. Prefer the former.
/// #[field(validate = eq(Pet::Dog))]
/// #[field(validate = with(|p| *p == Pet::Dog, "expected a dog"))]
/// dog: Pet,
/// // These are equivalent. Prefer the former.
/// #[field(validate = contains(&self.dog))]
/// #[field(validate = with(|pets| pets.iter().any(|p| p == &self.dog), "missing dog"))]
/// one_dog_please: Vec<Pet>,
/// }
/// ```