rocket/form/
strict.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 strictly.
7///
8/// This type implements the [`FromForm`] trait and thus can be used as a
9/// generic parameter to the [`Form`] data guard: `Form<Strict<T>>`, where `T`
10/// implements `FromForm`. Unlike using `Form` directly, this type uses a
11/// _strict_ parsing strategy: forms that contains a superset of the expected
12/// fields (i.e, extra fields) will fail to parse and defaults will not be use
13/// for missing fields.
14///
15/// # Strictness
16///
17/// A `Strict<T>` will parse successfully from an incoming form only if
18/// the form contains the exact set of fields in `T`. Said another way, a
19/// `Strict<T>` will error on missing and/or extra fields. For instance, if an
20/// incoming form contains the fields "a", "b", and "c" while `T` only contains
21/// "a" and "c", the form _will not_ parse as `Strict<T>`.
22///
23/// # Usage
24///
25/// `Strict<T>` implements [`FromForm`] as long as `T` implements `FromForm`. As
26/// such, `Form<Strict<T>>` is a data guard:
27///
28/// ```rust
29/// # #[macro_use] extern crate rocket;
30/// use rocket::form::{Form, Strict};
31///
32/// #[derive(FromForm)]
33/// struct UserInput {
34///     value: String
35/// }
36///
37/// #[post("/submit", data = "<user_input>")]
38/// fn submit_task(user_input: Form<Strict<UserInput>>) -> String {
39///     format!("Your value: {}", user_input.value)
40/// }
41/// ```
42///
43/// `Strict` can also be used to make individual fields strict while keeping the
44/// overall structure and remaining fields lenient:
45///
46/// ```rust
47/// # #[macro_use] extern crate rocket;
48/// use rocket::form::{Form, Strict};
49///
50/// #[derive(FromForm)]
51/// struct UserInput {
52///     required: Strict<bool>,
53///     uses_default: bool
54/// }
55/// ```
56#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
57pub struct Strict<T>(T);
58
59impl<T> Strict<T> {
60    /// Consumes `self` and returns the inner value.
61    ///
62    /// Note that since `Strict` implements [`Deref`] and [`DerefMut`] with
63    /// target `T`, reading and writing an inner value can be accomplished
64    /// transparently.
65    ///
66    /// # Example
67    ///
68    /// ```rust
69    /// # #[macro_use] extern crate rocket;
70    /// use rocket::form::{Form, Strict};
71    ///
72    /// #[derive(FromForm)]
73    /// struct MyForm {
74    ///     field: String,
75    /// }
76    ///
77    /// #[post("/submit", data = "<form>")]
78    /// fn submit(form: Form<Strict<MyForm>>) -> String {
79    ///     // We can read or mutate a value transparently:
80    ///     let field: &str = &form.field;
81    ///
82    ///     // To gain ownership, however, use `into_inner()`:
83    ///     form.into_inner().into_inner().field
84    /// }
85    /// ```
86    pub fn into_inner(self) -> T {
87        self.0
88    }
89}
90
91#[crate::async_trait]
92impl<'v, T: FromForm<'v>> FromForm<'v> for Strict<T> {
93    type Context = T::Context;
94
95    #[inline(always)]
96    fn init(_: Options) -> Self::Context {
97        T::init(Options { strict: true })
98    }
99
100    #[inline(always)]
101    fn push_value(ctxt: &mut Self::Context, field: ValueField<'v>) {
102        T::push_value(ctxt, field)
103    }
104
105    #[inline(always)]
106    async fn push_data(ctxt: &mut Self::Context, field: DataField<'v, '_>) {
107        T::push_data(ctxt, field).await
108    }
109
110    #[inline(always)]
111    fn finalize(this: Self::Context) -> Result<'v, Self> {
112        T::finalize(this).map(Self)
113    }
114}
115
116impl<T> Deref for Strict<T> {
117    type Target = T;
118
119    fn deref(&self) -> &Self::Target {
120        &self.0
121    }
122}
123
124impl<T> DerefMut for Strict<T> {
125    fn deref_mut(&mut self) -> &mut Self::Target {
126        &mut self.0
127    }
128}
129
130impl<T> From<T> for Strict<T> {
131    #[inline]
132    fn from(val: T) -> Strict<T> {
133        Strict(val)
134    }
135}
136
137impl<'f, A, T: FromUriParam<Query, A> + FromForm<'f>> FromUriParam<Query, A> for Strict<T> {
138    type Target = T::Target;
139
140    #[inline(always)]
141    fn from_uri_param(param: A) -> Self::Target {
142        T::from_uri_param(param)
143    }
144}