mirror of https://github.com/rwf2/Rocket.git
Allow ignoring unused items in query string with #[derive(FromFormIgnorable)].
This commit is contained in:
parent
f5ec470a7d
commit
0522ed0537
|
@ -49,9 +49,38 @@ fn get_struct_lifetime(ecx: &mut ExtCtxt, item: &Annotatable, span: Span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use proper logging to emit the error messages.
|
trait IgnoreExtraFieldStrategy {
|
||||||
|
fn shall_ignore() -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IgnoreExtraField;
|
||||||
|
impl IgnoreExtraFieldStrategy for IgnoreExtraField {
|
||||||
|
fn shall_ignore() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProhibitExtraField;
|
||||||
|
impl IgnoreExtraFieldStrategy for ProhibitExtraField {
|
||||||
|
fn shall_ignore() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_form_derive(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
|
pub fn from_form_derive(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
|
||||||
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
||||||
|
from_form_derive_imp::<ProhibitExtraField>(ecx, span, meta_item, annotated, push)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_form_ignorable_derive(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
|
||||||
|
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
||||||
|
from_form_derive_imp::<IgnoreExtraField>(ecx, span, meta_item, annotated, push)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Use proper logging to emit the error messages.
|
||||||
|
fn from_form_derive_imp<S: IgnoreExtraFieldStrategy>
|
||||||
|
(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
|
||||||
|
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
||||||
let struct_lifetime = get_struct_lifetime(ecx, annotated, span);
|
let struct_lifetime = get_struct_lifetime(ecx, annotated, span);
|
||||||
let (lifetime_var, trait_generics) = match struct_lifetime {
|
let (lifetime_var, trait_generics) = match struct_lifetime {
|
||||||
lifetime@Some(_) => (lifetime, ty::LifetimeBounds::empty()),
|
lifetime@Some(_) => (lifetime, ty::LifetimeBounds::empty()),
|
||||||
|
@ -110,7 +139,7 @@ pub fn from_form_derive(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
|
||||||
),
|
),
|
||||||
attributes: vec![],
|
attributes: vec![],
|
||||||
is_unsafe: false,
|
is_unsafe: false,
|
||||||
combine_substructure: c_s(Box::new(from_form_substructure)),
|
combine_substructure: c_s(Box::new(from_form_substructure::<S>)),
|
||||||
unify_fieldless_variants: false,
|
unify_fieldless_variants: false,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -122,7 +151,8 @@ pub fn from_form_derive(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
|
||||||
trait_def.expand(ecx, meta_item, annotated, push);
|
trait_def.expand(ecx, meta_item, annotated, push);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_form_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
|
fn from_form_substructure<S: IgnoreExtraFieldStrategy>
|
||||||
|
(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
|
||||||
// Check that we specified the methods to the argument correctly.
|
// Check that we specified the methods to the argument correctly.
|
||||||
const EXPECTED_ARGS: usize = 1;
|
const EXPECTED_ARGS: usize = 1;
|
||||||
let arg = if substr.nonself_args.len() == EXPECTED_ARGS {
|
let arg = if substr.nonself_args.len() == EXPECTED_ARGS {
|
||||||
|
@ -197,6 +227,9 @@ fn from_form_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substruct
|
||||||
|
|
||||||
// The actual match statement. Iterate through all of the fields in the form
|
// The actual match statement. Iterate through all of the fields in the form
|
||||||
// and use the $arms generated above.
|
// and use the $arms generated above.
|
||||||
|
|
||||||
|
let shall_ignore = S::shall_ignore();
|
||||||
|
|
||||||
stmts.push(quote_stmt!(cx,
|
stmts.push(quote_stmt!(cx,
|
||||||
for (k, v) in $arg {
|
for (k, v) in $arg {
|
||||||
match k.as_str() {
|
match k.as_str() {
|
||||||
|
@ -207,9 +240,11 @@ fn from_form_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substruct
|
||||||
* in sync with Rocket::preprocess. */
|
* in sync with Rocket::preprocess. */
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!(" => {}={} has no matching field in struct.",
|
if !$shall_ignore {
|
||||||
k, v);
|
println!(" => {}={} has no matching field in struct.",
|
||||||
$return_err_stmt
|
k, v);
|
||||||
|
$return_err_stmt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,8 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
reg.register_macro("errors", macros::errors);
|
reg.register_macro("errors", macros::errors);
|
||||||
|
|
||||||
register_derives!(reg,
|
register_derives!(reg,
|
||||||
"derive_FromForm" => from_form_derive
|
"derive_FromForm" => from_form_derive,
|
||||||
|
"derive_FromFormIgnorable" => from_form_ignorable_derive
|
||||||
);
|
);
|
||||||
|
|
||||||
register_decorators!(reg,
|
register_decorators!(reg,
|
||||||
|
|
|
@ -12,6 +12,12 @@ struct TodoTask {
|
||||||
completed: bool
|
completed: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, FromFormIgnorable)]
|
||||||
|
struct TodoTaskIgnorable {
|
||||||
|
description: String,
|
||||||
|
completed: bool
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Make deriving `FromForm` for this enum possible.
|
// TODO: Make deriving `FromForm` for this enum possible.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum FormOption {
|
enum FormOption {
|
||||||
|
@ -94,6 +100,27 @@ fn main() {
|
||||||
completed: false
|
completed: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Same number of arguments: simple case.
|
||||||
|
let task: Option<TodoTaskIgnorable> = parse("description=Hello&completed=on");
|
||||||
|
assert_eq!(task, Some(TodoTaskIgnorable {
|
||||||
|
description: "Hello".to_string(),
|
||||||
|
completed: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Argument in string but not in form.
|
||||||
|
let task: Option<TodoTaskIgnorable> = parse("other=a&description=Hello&completed=on");
|
||||||
|
assert_eq!(task, Some(TodoTaskIgnorable {
|
||||||
|
description: "Hello".to_string(),
|
||||||
|
completed: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Ensure _method isn't required.
|
||||||
|
let task: Option<TodoTaskIgnorable> = parse("_method=patch&description=Hello&completed=off");
|
||||||
|
assert_eq!(task, Some(TodoTaskIgnorable {
|
||||||
|
description: "Hello".to_string(),
|
||||||
|
completed: false
|
||||||
|
}));
|
||||||
|
|
||||||
let form_string = &[
|
let form_string = &[
|
||||||
"password=testing", "checkbox=off", "checkbox=on", "number=10",
|
"password=testing", "checkbox=off", "checkbox=on", "number=10",
|
||||||
"checkbox=off", "textarea=", "select=a", "radio=c",
|
"checkbox=off", "textarea=", "select=a", "radio=c",
|
||||||
|
|
Loading…
Reference in New Issue