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}