rocket/request/form/from_form.rs
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
use request::FormItems;
/// Trait to create an instance of some type from an HTTP form.
/// [`Form`](::request::Form) requires its generic type to implement this trait.
///
/// # Deriving
///
/// This trait can be automatically derived. When deriving `FromForm`, every
/// field in the structure must implement
/// [`FromFormValue`](::request::FromFormValue). Rocket validates each field in
/// the structure by calling its `FromFormValue` implementation. You may wish to
/// implement `FromFormValue` for your own types for custom, automatic
/// validation.
///
/// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #![allow(deprecated, dead_code, unused_attributes)]
/// # #[macro_use] extern crate rocket;
/// #[derive(FromForm)]
/// struct TodoTask {
/// description: String,
/// completed: bool
/// }
/// # fn main() { }
/// ```
///
/// # Data Guard
///
/// Types that implement `FromForm` can be parsed directly from incoming form
/// data via the `data` parameter and `Form` type.
///
/// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #![allow(deprecated, dead_code, unused_attributes)]
/// # #[macro_use] extern crate rocket;
/// # use rocket::request::Form;
/// # #[derive(FromForm)]
/// # struct TodoTask { description: String, completed: bool }
/// #[post("/submit", data = "<task>")]
/// fn submit_task(task: Form<TodoTask>) -> String {
/// format!("New task: {}", task.description)
/// }
/// # fn main() { }
/// ```
///
/// # Implementing
///
/// Implementing `FromForm` should be a rare occurrence. Prefer instead to use
/// Rocket's built-in derivation.
///
/// When implementing `FromForm`, use the [`FormItems`] iterator to iterate
/// through the raw form key/value pairs. Be aware that form fields that are
/// typically hidden from your application, such as `_method`, will be present
/// while iterating. Ensure that you adhere to the properties of the `strict`
/// parameter, as detailed in the documentation below.
///
/// ## Example
///
/// Consider the following scenario: we have a struct `Item` with field name
/// `field`. We'd like to parse any form that has a field named either `balloon`
/// _or_ `space`, and we'd like that field's value to be the value for our
/// structure's `field`. The following snippet shows how this would be
/// implemented:
///
/// ```rust
/// use rocket::request::{FromForm, FormItems};
///
/// struct Item {
/// field: String
/// }
///
/// impl<'f> FromForm<'f> for Item {
/// // In practice, we'd use a more descriptive error type.
/// type Error = ();
///
/// fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<Item, ()> {
/// let mut field = None;
///
/// for item in items {
/// match item.key.as_str() {
/// "balloon" | "space" if field.is_none() => {
/// let decoded = item.value.url_decode().map_err(|_| ())?;
/// field = Some(decoded);
/// }
/// _ if strict => return Err(()),
/// _ => { /* allow extra value when not strict */ }
/// }
/// }
///
/// field.map(|field| Item { field }).ok_or(())
/// }
/// }
/// ```
pub trait FromForm<'f>: Sized {
/// The associated error to be returned when parsing fails.
type Error;
/// Parses an instance of `Self` from the iterator of form items `it`.
///
/// Extra form field are allowed when `strict` is `false` and disallowed
/// when `strict` is `true`.
///
/// # Errors
///
/// If `Self` cannot be parsed from the given form items, an instance of
/// `Self::Error` will be returned.
///
/// When `strict` is `true` and unexpected, extra fields are present in
/// `it`, an instance of `Self::Error` will be returned.
fn from_form(it: &mut FormItems<'f>, strict: bool) -> Result<Self, Self::Error>;
}
impl<'f, T: FromForm<'f>> FromForm<'f> for Option<T> {
type Error = !;
#[inline]
fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<Option<T>, !> {
Ok(T::from_form(items, strict).ok())
}
}
impl<'f, T: FromForm<'f>> FromForm<'f> for Result<T, T::Error> {
type Error = !;
#[inline]
fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<Self, !> {
Ok(T::from_form(items, strict))
}
}