rocket/form/
lenient.rs

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