pub trait FromFormField<'v>: Send + Sized {
// Provided methods
fn from_value(field: ValueField<'v>) -> Result<'v, Self> { ... }
fn from_data<'life0, 'async_trait>(
field: DataField<'v, 'life0>,
) -> Pin<Box<dyn Future<Output = Result<'v, Self>> + Send + 'async_trait>>
where Self: 'async_trait,
'v: 'async_trait,
'life0: 'async_trait { ... }
fn default() -> Option<Self> { ... }
}Expand description
Implied form guard (FromForm) for parsing a single form field.
Types that implement FromFormField automatically implement FromForm
via a blanket implementation. As such, all FromFormField types are form
guards and can appear as the type of values in derived FromForm struct
fields:
#[derive(FromForm)]
struct Person<'r> {
name: &'r str,
age: u16
}§Semantics
The implementation of FromForm for a T: FromFormField type operates as
follows:
-
When parsing is strict, the parser accepts the first value or data field with the corresponding field name and calls
T::from_value()orT::from_data()with the field’s value, respectively. If more than one field value is seen, an [ErrorKind::Duplicate) is emitted. If no matching field is seen, anErrorKind::Missingis emitted. Otherwise, the result from the call is emitted. -
When parsing is lenient, the parser accepts the first expected value or data field with the corresponding field name and calls
T::from_value()orT::from_data()with the field’s value, respectively. Unexpected values, identified by returning anErrorKind::Unexpectedfromfrom_value()orfrom_data()are ignored. Any additional fields with a matching field name are ignored. If no matching field is seen andThas a default, it is used, otherwise anErrorKind::Missingis emitted.
§Deriving
FromFormField can be derived for C-like enums, where the generated
implementation case-insensitively parses fields with values equal to the
name of the variant or the value in field().
/// Fields with value `"simple"` parse as `Kind::Simple`. Fields with value
/// `"fancy"` parse as `Kind::SoFancy`.
#[derive(FromFormField)]
enum Kind {
Simple,
#[field(value = "fancy")]
SoFancy,
}§Provided Implementations
See FromForm for a list
of all form guards, including those implemented via FromFormField.
§Implementing
Implementing FromFormField requires implementing one or both of
from_value or from_data, depending on whether the type can be parsed
from a value field (text) and/or streaming binary data. Typically, a value
can be parsed from either, either directly or by using request-local cache
as an intermediary, and parsing from both should be preferred when sensible.
FromFormField is an async trait, so implementations must be decorated with
an attribute of #[rocket::async_trait]:
use rocket::form::{self, FromFormField, DataField, ValueField};
#[rocket::async_trait]
impl<'r> FromFormField<'r> for MyType {
fn from_value(field: ValueField<'r>) -> form::Result<'r, Self> {
todo!("parse from a value or use default impl")
}
async fn from_data(field: DataField<'r, '_>) -> form::Result<'r, Self> {
todo!("parse from a value or use default impl")
}
}§Example
The following example parses a custom Person type with the format
$name:$data, where $name is expected to be string and data is expected
to be any slice of bytes.
use rocket::data::ToByteUnit;
use rocket::form::{self, FromFormField, DataField, ValueField};
use memchr::memchr;
struct Person<'r> {
name: &'r str,
data: &'r [u8]
}
#[rocket::async_trait]
impl<'r> FromFormField<'r> for Person<'r> {
fn from_value(field: ValueField<'r>) -> form::Result<'r, Self> {
match field.value.find(':') {
Some(i) => Ok(Person {
name: &field.value[..i],
data: field.value[(i + 1)..].as_bytes()
}),
None => Err(form::Error::validation("does not contain ':'"))?
}
}
async fn from_data(field: DataField<'r, '_>) -> form::Result<'r, Self> {
// Retrieve the configured data limit or use `256KiB` as default.
let limit = field.request.limits()
.get("person")
.unwrap_or(256.kibibytes());
// Read the capped data stream, returning a limit error as needed.
let bytes = field.data.open(limit).into_bytes().await?;
if !bytes.is_complete() {
Err((None, Some(limit)))?;
}
// Store the bytes in request-local cache and split at ':'.
let bytes = bytes.into_inner();
let bytes = rocket::request::local_cache!(field.request, bytes);
let (raw_name, data) = match memchr(b':', bytes) {
Some(i) => (&bytes[..i], &bytes[(i + 1)..]),
None => Err(form::Error::validation("does not contain ':'"))?
};
// Try to parse the name as UTF-8 or return an error if it fails.
let name = std::str::from_utf8(raw_name)?;
Ok(Person { name, data })
}
}
use rocket::form::{Form, FromForm};
// The type can be used directly, if only one field is expected...
#[post("/person", data = "<person>")]
fn person(person: Form<Person<'_>>) { /* ... */ }
// ...or as a named field in another form guard...
#[derive(FromForm)]
struct NewPerson<'r> {
person: Person<'r>
}
#[post("/person", data = "<person>")]
fn new_person(person: Form<NewPerson<'_>>) { /* ... */ }Provided Methods§
Sourcefn from_value(field: ValueField<'v>) -> Result<'v, Self>
fn from_value(field: ValueField<'v>) -> Result<'v, Self>
Parse a value of T from a form value field.
The default implementation returns an error of
ValueField::unexpected().
Sourcefn from_data<'life0, 'async_trait>(
field: DataField<'v, 'life0>,
) -> Pin<Box<dyn Future<Output = Result<'v, Self>> + Send + 'async_trait>>where
Self: 'async_trait,
'v: 'async_trait,
'life0: 'async_trait,
fn from_data<'life0, 'async_trait>(
field: DataField<'v, 'life0>,
) -> Pin<Box<dyn Future<Output = Result<'v, Self>> + Send + 'async_trait>>where
Self: 'async_trait,
'v: 'async_trait,
'life0: 'async_trait,
Parse a value of T from a form data field.
The default implementation returns an error of
DataField::unexpected().
Sourcefn default() -> Option<Self>
fn default() -> Option<Self>
Returns a default value, if any exists, to be used during lenient parsing when the form field is missing.
A return value of None means that field is required to exist and parse
successfully, always. A return value of Some(default) means that
default should be used when a field is missing.
The default implementation returns None.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.