rocket/form/lenient.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
use std::ops::{Deref, DerefMut};
use crate::form::prelude::*;
use crate::http::uri::fmt::{Query, FromUriParam};
/// A form guard for parsing form types leniently.
///
/// This type implements the [`FromForm`] trait and thus can be used as a
/// generic parameter to the [`Form`] data guard: `Form<Lenient<T>>`, where `T`
/// implements `FromForm`. Unlike using `Form` directly, this type uses a
/// _lenient_ parsing strategy.
///
/// # Lenient Parsing
///
/// A `Lenient<T>` will parse successfully from an incoming form even if the
/// form contains extra or missing fields. If fields are missing, the form field
/// type's default will be used, if there is one. Extra fields are ignored; only
/// the first is parsed and validated. This is the default strategy for
/// [`Form`].
///
/// # Usage
///
/// `Lenient<T>` implements [`FromForm`] as long as `T` implements `FromForm`.
/// As such, `Form<Lenient<T>>` is a data guard.
///
/// Note that `Form<T>` _already_ parses leniently, so a `Form<Lenient<T>>` is
/// redundant and equal to `Form<T>`. `Lenient`, however, can be used to make
/// otherwise strict parses lenient, for example, in `Option<Lenient<T>>`:
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::form::Lenient;
///
/// #[derive(FromForm)]
/// struct UserInput {
/// // Parses as `Some(false)` when `lenient_inner_option` isn't present.
/// // Without `Lenient`, this would otherwise parse as `None`.
/// lenient_inner_option: Option<Lenient<bool>>,
/// }
/// ```
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Lenient<T>(T);
impl<T> Lenient<T> {
/// Consumes `self` and returns the inner value.
///
/// Note that since `Lenient` implements [`Deref`] and [`DerefMut`] with
/// target `T`, reading and writing an inner value can be accomplished
/// transparently.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::form::{Form, Lenient};
///
/// #[derive(FromForm)]
/// struct MyForm {
/// field: String,
/// }
///
/// #[post("/submit", data = "<form>")]
/// fn submit(form: Form<Lenient<MyForm>>) -> String {
/// // We can read or mutate a value transparently:
/// let field: &str = &form.field;
///
/// // To gain ownership, however, use `into_inner()`:
/// form.into_inner().into_inner().field
/// }
/// ```
pub fn into_inner(self) -> T {
self.0
}
}
#[crate::async_trait]
impl<'v, T: FromForm<'v>> FromForm<'v> for Lenient<T> {
type Context = T::Context;
#[inline(always)]
fn init(opts: Options) -> Self::Context {
T::init(Options { strict: false, ..opts })
}
#[inline(always)]
fn push_value(ctxt: &mut Self::Context, field: ValueField<'v>) {
T::push_value(ctxt, field)
}
#[inline(always)]
async fn push_data(ctxt: &mut Self::Context, field: DataField<'v, '_>) {
T::push_data(ctxt, field).await
}
#[inline(always)]
fn finalize(this: Self::Context) -> Result<'v, Self> {
T::finalize(this).map(Self)
}
}
impl<T> Deref for Lenient<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Lenient<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<T> for Lenient<T> {
#[inline]
fn from(val: T) -> Lenient<T> {
Lenient(val)
}
}
impl<'f, A, T: FromUriParam<Query, A> + FromForm<'f>> FromUriParam<Query, A> for Lenient<T> {
type Target = T::Target;
#[inline(always)]
fn from_uri_param(param: A) -> Self::Target {
T::from_uri_param(param)
}
}