logo
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::ops::{Deref, DerefMut};

use crate::form::prelude::*;
use crate::http::uri::fmt::{Query, FromUriParam};

/// A form guard for parsing form types strictly.
///
/// This type implements the [`FromForm`] trait and thus can be used as a
/// generic parameter to the [`Form`] data guard: `Form<Strict<T>>`, where `T`
/// implements `FromForm`. Unlike using `Form` directly, this type uses a
/// _strict_ parsing strategy: forms that contains a superset of the expected
/// fields (i.e, extra fields) will fail to parse and defaults will not be use
/// for missing fields.
///
/// # Strictness
///
/// A `Strict<T>` will parse successfully from an incoming form only if
/// the form contains the exact set of fields in `T`. Said another way, a
/// `Strict<T>` will error on missing and/or extra fields. For instance, if an
/// incoming form contains the fields "a", "b", and "c" while `T` only contains
/// "a" and "c", the form _will not_ parse as `Strict<T>`.
///
/// # Usage
///
/// `Strict<T>` implements [`FromForm`] as long as `T` implements `FromForm`. As
/// such, `Form<Strict<T>>` is a data guard:
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::form::{Form, Strict};
///
/// #[derive(FromForm)]
/// struct UserInput {
///     value: String
/// }
///
/// #[post("/submit", data = "<user_input>")]
/// fn submit_task(user_input: Form<Strict<UserInput>>) -> String {
///     format!("Your value: {}", user_input.value)
/// }
/// ```
///
/// `Strict` can also be used to make individual fields strict while keeping the
/// overall structure and remaining fields lenient:
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use rocket::form::{Form, Strict};
///
/// #[derive(FromForm)]
/// struct UserInput {
///     required: Strict<bool>,
///     uses_default: bool
/// }
/// ```
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Strict<T>(T);

impl<T> Strict<T> {
    /// Consumes `self` and returns the inner value.
    ///
    /// Note that since `Strict` 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, Strict};
    ///
    /// #[derive(FromForm)]
    /// struct MyForm {
    ///     field: String,
    /// }
    ///
    /// #[post("/submit", data = "<form>")]
    /// fn submit(form: Form<Strict<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 Strict<T> {
    type Context = T::Context;

    #[inline(always)]
    fn init(opts: Options) -> Self::Context {
        T::init(Options { strict: true, ..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 Strict<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> DerefMut for Strict<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<T> From<T> for Strict<T> {
    #[inline]
    fn from(val: T) -> Strict<T> {
        Strict(val)
    }
}

impl<'f, A, T: FromUriParam<Query, A> + FromForm<'f>> FromUriParam<Query, A> for Strict<T> {
    type Target = T::Target;

    #[inline(always)]
    fn from_uri_param(param: A) -> Self::Target {
        T::from_uri_param(param)
    }
}