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}