mirror of https://github.com/rwf2/Rocket.git
Allow multiple and uncased field renamings.
This commit is contained in:
parent
f0a6b9a25a
commit
7784cc982a
|
@ -78,7 +78,7 @@ impl Parameter {
|
||||||
impl Dynamic {
|
impl Dynamic {
|
||||||
// This isn't public since this `Dynamic` should always be an `Ignored`.
|
// This isn't public since this `Dynamic` should always be an `Ignored`.
|
||||||
pub fn is_wild(&self) -> bool {
|
pub fn is_wild(&self) -> bool {
|
||||||
self.name == "_"
|
&self.name == "_"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,7 @@ impl Route {
|
||||||
.chain(query_params.iter().filter_map(|p| p.guard()))
|
.chain(query_params.iter().filter_map(|p| p.guard()))
|
||||||
.chain(data_guard.as_ref().into_iter());
|
.chain(data_guard.as_ref().into_iter());
|
||||||
|
|
||||||
all_other_guards.all(|g| g.name != name)
|
all_other_guards.all(|g| &g.name != *name)
|
||||||
})
|
})
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, (name, (ident, ty)))| Guard {
|
.map(|(index, (name, (ident, ty)))| Guard {
|
||||||
|
|
|
@ -3,18 +3,19 @@ use devise::{*, ext::{TypeExt, SpanDiagnosticExt}};
|
||||||
use syn::visit_mut::VisitMut;
|
use syn::visit_mut::VisitMut;
|
||||||
use syn::visit::Visit;
|
use syn::visit::Visit;
|
||||||
|
|
||||||
use crate::proc_macro2::{Span, TokenStream, TokenTree};
|
use crate::proc_macro2::{TokenStream, TokenTree};
|
||||||
use crate::syn_ext::IdentExt;
|
use crate::syn_ext::IdentExt;
|
||||||
use crate::name::Name;
|
use crate::name::Name;
|
||||||
|
|
||||||
pub struct FormField {
|
#[derive(Debug)]
|
||||||
pub span: Span,
|
pub enum FieldName {
|
||||||
pub name: Name,
|
Cased(Name),
|
||||||
|
Uncased(Name),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromMeta)]
|
#[derive(FromMeta)]
|
||||||
pub struct FieldAttr {
|
pub struct FieldAttr {
|
||||||
pub name: Option<FormField>,
|
pub name: Option<FieldName>,
|
||||||
pub validate: Option<SpanWrapped<syn::Expr>>,
|
pub validate: Option<SpanWrapped<syn::Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +25,13 @@ impl FieldAttr {
|
||||||
|
|
||||||
pub(crate) trait FieldExt {
|
pub(crate) trait FieldExt {
|
||||||
fn ident(&self) -> &syn::Ident;
|
fn ident(&self) -> &syn::Ident;
|
||||||
fn field_name(&self) -> Result<String>;
|
fn field_names(&self) -> Result<Vec<FieldName>>;
|
||||||
|
fn one_field_name(&self) -> Result<FieldName>;
|
||||||
fn stripped_ty(&self) -> syn::Type;
|
fn stripped_ty(&self) -> syn::Type;
|
||||||
fn name_view(&self) -> Result<syn::Expr>;
|
fn name_view(&self) -> Result<syn::Expr>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromMeta for FormField {
|
impl FromMeta for FieldName {
|
||||||
fn from_meta(meta: &MetaItem) -> Result<Self> {
|
fn from_meta(meta: &MetaItem) -> Result<Self> {
|
||||||
// These are used during parsing.
|
// These are used during parsing.
|
||||||
const CONTROL_CHARS: &[char] = &['&', '=', '?', '.', '[', ']'];
|
const CONTROL_CHARS: &[char] = &['&', '=', '?', '.', '[', ']'];
|
||||||
|
@ -44,8 +46,23 @@ impl FromMeta for FormField {
|
||||||
s.chars().all(|c| c.is_ascii_graphic() && !CONTROL_CHARS.contains(&c))
|
s.chars().all(|c| c.is_ascii_graphic() && !CONTROL_CHARS.contains(&c))
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = Name::from_meta(meta)?;
|
let field_name = match Name::from_meta(meta) {
|
||||||
if !is_valid_field_name(name.as_str()) {
|
Ok(name) => FieldName::Cased(name),
|
||||||
|
Err(_) => {
|
||||||
|
#[derive(FromMeta)]
|
||||||
|
struct Inner {
|
||||||
|
#[meta(naked)]
|
||||||
|
uncased: Name
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr = meta.expr()?;
|
||||||
|
let item: MetaItem = syn::parse2(quote!(#expr))?;
|
||||||
|
let inner = Inner::from_meta(&item)?;
|
||||||
|
FieldName::Uncased(inner.uncased)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !is_valid_field_name(field_name.as_str()) {
|
||||||
let chars = CONTROL_CHARS.iter()
|
let chars = CONTROL_CHARS.iter()
|
||||||
.map(|c| format!("{:?}", c))
|
.map(|c| format!("{:?}", c))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -56,7 +73,35 @@ impl FromMeta for FormField {
|
||||||
.help(format!("field name cannot be `isindex` or contain {}", chars)));
|
.help(format!("field name cannot be `isindex` or contain {}", chars)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(FormField { span: meta.value_span(), name })
|
Ok(field_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for FieldName {
|
||||||
|
type Target = Name;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
FieldName::Cased(n) | FieldName::Uncased(n) => n,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl quote::ToTokens for FieldName {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
(self as &Name).to_tokens(tokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for FieldName {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
use FieldName::*;
|
||||||
|
|
||||||
|
match (self, other) {
|
||||||
|
(Cased(a), Cased(b)) => a == b,
|
||||||
|
(Cased(a), Uncased(u)) | (Uncased(u), Cased(a)) => a == u.as_uncased_str(),
|
||||||
|
(Uncased(u1), Uncased(u2)) => u1.as_uncased_str() == u2.as_uncased_str(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,22 +110,31 @@ impl FieldExt for Field<'_> {
|
||||||
self.ident.as_ref().expect("named")
|
self.ident.as_ref().expect("named")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn field_name(&self) -> Result<String> {
|
fn field_names(&self) -> Result<Vec<FieldName>> {
|
||||||
let mut fields = FieldAttr::from_attrs(FieldAttr::NAME, &self.attrs)?
|
let attr_names = FieldAttr::from_attrs(FieldAttr::NAME, &self.attrs)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|attr| attr.name);
|
.filter_map(|attr| attr.name)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let name = fields.next()
|
if attr_names.is_empty() {
|
||||||
.map(|f| f.name)
|
let ident_name = Name::from(self.ident());
|
||||||
.unwrap_or_else(|| Name::from(self.ident().clone()));
|
return Ok(vec![FieldName::Cased(ident_name)]);
|
||||||
|
|
||||||
if let Some(field) = fields.next() {
|
|
||||||
return Err(field.span
|
|
||||||
.error("duplicate form field renaming")
|
|
||||||
.help("a field can only be renamed once"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(name.to_string())
|
Ok(attr_names)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn one_field_name(&self) -> Result<FieldName> {
|
||||||
|
let mut names = self.field_names()?.into_iter();
|
||||||
|
let first = names.next().expect("always have >= 1 name");
|
||||||
|
|
||||||
|
if let Some(name) = names.next() {
|
||||||
|
return Err(name.span()
|
||||||
|
.error("unexpected second field name")
|
||||||
|
.note("only one field rename is allowed in this context"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(first)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stripped_ty(&self) -> syn::Type {
|
fn stripped_ty(&self) -> syn::Type {
|
||||||
|
@ -88,7 +142,8 @@ impl FieldExt for Field<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name_view(&self) -> Result<syn::Expr> {
|
fn name_view(&self) -> Result<syn::Expr> {
|
||||||
let field_name = self.field_name()?;
|
let field_names = self.field_names()?;
|
||||||
|
let field_name = field_names.first().expect("always have name");
|
||||||
define_spanned_export!(self.span() => _form);
|
define_spanned_export!(self.span() => _form);
|
||||||
let name_view = quote_spanned! { self.span() =>
|
let name_view = quote_spanned! { self.span() =>
|
||||||
#_form::NameBuf::from((__c.__parent, #field_name))
|
#_form::NameBuf::from((__c.__parent, #field_name))
|
||||||
|
|
|
@ -2,25 +2,30 @@ use devise::{*, ext::{TypeExt, SpanDiagnosticExt, GenericsExt, Split2, quote_res
|
||||||
|
|
||||||
use crate::exports::*;
|
use crate::exports::*;
|
||||||
use crate::proc_macro2::TokenStream;
|
use crate::proc_macro2::TokenStream;
|
||||||
use crate::derive::form_field::*;
|
use crate::derive::form_field::{*, FieldName::*};
|
||||||
|
|
||||||
// F: fn(field_ty: Ty, field_context: Expr)
|
// F: fn(field_ty: Ty, field_context: Expr)
|
||||||
fn fields_map<F>(fields: Fields<'_>, map_f: F) -> Result<TokenStream>
|
fn fields_map<F>(fields: Fields<'_>, map_f: F) -> Result<TokenStream>
|
||||||
where F: Fn(&syn::Type, &syn::Expr) -> TokenStream
|
where F: Fn(&syn::Type, &syn::Expr) -> TokenStream
|
||||||
{
|
{
|
||||||
let matchers = fields.iter()
|
let mut matchers = vec![];
|
||||||
.map(|f| {
|
for field in fields.iter() {
|
||||||
let (ident, field_name, ty) = (f.ident(), f.field_name()?, f.stripped_ty());
|
let (ident, ty) = (field.ident(), field.stripped_ty());
|
||||||
let field_context = quote_spanned!(ty.span() => {
|
let field_context = quote_spanned!(ty.span() => {
|
||||||
let _o = __c.__opts;
|
let _o = __c.__opts;
|
||||||
__c.#ident.get_or_insert_with(|| <#ty as #_form::FromForm<'__f>>::init(_o))
|
__c.#ident.get_or_insert_with(|| <#ty as #_form::FromForm<'__f>>::init(_o))
|
||||||
});
|
});
|
||||||
|
|
||||||
let field_context = syn::parse2(field_context).expect("valid expr");
|
let field_names = field.field_names()?;
|
||||||
let expr = map_f(&ty, &field_context);
|
let field_context = syn::parse2(field_context).expect("valid expr");
|
||||||
Ok(quote!(#field_name => { #expr }))
|
let push = map_f(&ty, &field_context);
|
||||||
})
|
let field_matchers = field_names.iter().map(|f| match f {
|
||||||
.collect::<Result<Vec<TokenStream>>>()?;
|
Cased(name) => quote!(#name => { #push }),
|
||||||
|
Uncased(name) => quote!(__n if __n.as_uncased() == #name => { #push }),
|
||||||
|
});
|
||||||
|
|
||||||
|
matchers.extend(field_matchers);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
__c.__parent = __f.name.parent();
|
__c.__parent = __f.name.parent();
|
||||||
|
@ -65,15 +70,33 @@ pub fn derive_from_form(input: proc_macro::TokenStream) -> TokenStream {
|
||||||
return Err(fields.span().error("at least one field is required"));
|
return Err(fields.span().error("at least one field is required"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut names = ::std::collections::HashMap::new();
|
let mut names = vec![];
|
||||||
|
let mut field_map = vec![];
|
||||||
for field in fields.iter() {
|
for field in fields.iter() {
|
||||||
let name = field.field_name()?;
|
names.append(&mut field.field_names()?);
|
||||||
if let Some(span) = names.get(&name) {
|
field_map.push((names.len(), field));
|
||||||
return Err(field.span().error("duplicate form field")
|
}
|
||||||
.span_note(*span, "previously defined here"));
|
|
||||||
}
|
|
||||||
|
|
||||||
names.insert(name, field.span());
|
// get the field corresponding to name index `k`.
|
||||||
|
let field = |k| field_map.iter().find(|(i, _)| k < *i).expect("k < *i");
|
||||||
|
|
||||||
|
for (i, a) in names.iter().enumerate() {
|
||||||
|
let rest = names.iter().enumerate().skip(i + 1);
|
||||||
|
if let Some((j, b)) = rest.filter(|(_, b)| b == &a).next() {
|
||||||
|
let ((fa_i, field_a), (fb_i, field_b)) = (field(i), field(j));
|
||||||
|
|
||||||
|
if fa_i == fb_i {
|
||||||
|
return Err(field_a.span()
|
||||||
|
.error("field has conflicting names")
|
||||||
|
.span_note(a.span(), "this field name...")
|
||||||
|
.span_note(b.span(), "...conflicts with this name"));
|
||||||
|
} else {
|
||||||
|
return Err(b.span()
|
||||||
|
.error("field name conflicts with previous name")
|
||||||
|
.span_note(field_a.span(), "previous field with conflicting name")
|
||||||
|
.span_help(field_b.span(), "field name is part of this field"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -105,6 +128,10 @@ pub fn derive_from_form(input: proc_macro::TokenStream) -> TokenStream {
|
||||||
quote_spanned!(ty.span() => #ident: #field_ty,)
|
quote_spanned!(ty.span() => #ident: #field_ty,)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
.outer_mapper(quote! {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use #_http::uncased::AsUncased;
|
||||||
|
})
|
||||||
.outer_mapper(quote!(#[rocket::async_trait]))
|
.outer_mapper(quote!(#[rocket::async_trait]))
|
||||||
.inner_mapper(MapperBuild::new()
|
.inner_mapper(MapperBuild::new()
|
||||||
.try_input_map(|mapper, input| {
|
.try_input_map(|mapper, input| {
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub fn derive_from_form_field(input: proc_macro::TokenStream) -> TokenStream {
|
||||||
.try_enum_map(|_, data| {
|
.try_enum_map(|_, data| {
|
||||||
let variant_name_sources = data.variants()
|
let variant_name_sources = data.variants()
|
||||||
.map(|v| FieldAttr::one_from_attrs("field", &v.attrs).map(|o| {
|
.map(|v| FieldAttr::one_from_attrs("field", &v.attrs).map(|o| {
|
||||||
o.map(|f| f.value).unwrap_or_else(|| v.ident.clone().into())
|
o.map(|f| f.value).unwrap_or_else(|| Name::from(&v.ident))
|
||||||
}))
|
}))
|
||||||
.collect::<Result<Vec<Name>>>()?;
|
.collect::<Result<Vec<Name>>>()?;
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ pub fn derive_uri_display_query(input: proc_macro::TokenStream) -> TokenStream {
|
||||||
let span = field.span().into();
|
let span = field.span().into();
|
||||||
let accessor = field.accessor();
|
let accessor = field.accessor();
|
||||||
let tokens = if field.ident.is_some() {
|
let tokens = if field.ident.is_some() {
|
||||||
let name = field.field_name()?;
|
let name = field.one_field_name()?;
|
||||||
quote_spanned!(span => f.write_named_value(#name, &#accessor)?;)
|
quote_spanned!(span => f.write_named_value(#name, &#accessor)?;)
|
||||||
} else {
|
} else {
|
||||||
quote_spanned!(span => f.write_value(&#accessor)?;)
|
quote_spanned!(span => f.write_value(&#accessor)?;)
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
use crate::syn::{self, Ident, ext::IdentExt};
|
use crate::syn::{self, Ident, ext::IdentExt};
|
||||||
|
use crate::http::uncased::UncasedStr;
|
||||||
use crate::proc_macro2::Span;
|
use crate::proc_macro2::Span;
|
||||||
|
|
||||||
/// A "name" read by codegen, which may or may not be a valid identifier. A
|
/// A "name" read by codegen, which may or may not be an identifier. A `Name` is
|
||||||
/// `Name` is typically constructed indirectly via FromMeta, or From<Ident> or
|
/// typically constructed indirectly via FromMeta, or From<Ident> or directly
|
||||||
/// directly from a string via `Name::new()`.
|
/// from a string via `Name::new()`.
|
||||||
///
|
///
|
||||||
/// Some "names" in Rocket include:
|
/// Some "names" in Rocket include:
|
||||||
/// * Dynamic parameter: `name` in `<name>`
|
/// * Dynamic parameter: `name` in `<name>`
|
||||||
/// * Renamed fields: `foo` in #[field(name = "foo")].
|
/// * Renamed fields: `foo` in #[field(name = "foo")].
|
||||||
///
|
///
|
||||||
/// `Name` implements Hash, PartialEq, and Eq, and additionally PartialEq<S> for
|
/// `Name` implements Hash, PartialEq, and Eq, and additionally PartialEq<S> for
|
||||||
/// all types `S: AsStr<str>`. These implementations all compare the value of
|
/// all types `S: PartialEq<str>`. These implementations all compare the value
|
||||||
/// `name()` only.
|
/// of `as_str()` only.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Name {
|
pub struct Name {
|
||||||
value: String,
|
value: String,
|
||||||
|
@ -31,6 +32,11 @@ impl Name {
|
||||||
&self.value
|
&self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like `as_str()` but into an `&UncasedStr`.
|
||||||
|
pub fn as_uncased_str(&self) -> &UncasedStr {
|
||||||
|
UncasedStr::new(self.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
self.span
|
self.span
|
||||||
}
|
}
|
||||||
|
@ -50,7 +56,7 @@ impl devise::FromMeta for Name {
|
||||||
|
|
||||||
impl quote::ToTokens for Name {
|
impl quote::ToTokens for Name {
|
||||||
fn to_tokens(&self, tokens: &mut devise::proc_macro2::TokenStream) {
|
fn to_tokens(&self, tokens: &mut devise::proc_macro2::TokenStream) {
|
||||||
self.as_str().to_tokens(tokens)
|
syn::LitStr::new(self.as_str(), self.span()).to_tokens(tokens)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,12 +66,6 @@ impl From<&Ident> for Name {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Ident> for Name {
|
|
||||||
fn from(ident: Ident) -> Self {
|
|
||||||
Name::new(ident.unraw().to_string(), ident.span())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<str> for Name {
|
impl AsRef<str> for Name {
|
||||||
fn as_ref(&self) -> &str {
|
fn as_ref(&self) -> &str {
|
||||||
self.as_str()
|
self.as_str()
|
||||||
|
@ -88,9 +88,9 @@ impl std::ops::Deref for Name {
|
||||||
|
|
||||||
impl Eq for Name { }
|
impl Eq for Name { }
|
||||||
|
|
||||||
impl<S: AsRef<str> + ?Sized> PartialEq<S> for Name {
|
impl<S: PartialEq<str> + ?Sized> PartialEq<S> for Name {
|
||||||
fn eq(&self, other: &S) -> bool {
|
fn eq(&self, other: &S) -> bool {
|
||||||
self.as_str() == other.as_ref()
|
other == self.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,60 @@ fn field_renaming() {
|
||||||
|
|
||||||
let form: Option<RenamedForm> = strict(&form_string).ok();
|
let form: Option<RenamedForm> = strict(&form_string).ok();
|
||||||
assert!(form.is_none());
|
assert!(form.is_none());
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, FromForm)]
|
||||||
|
struct MultiName<'r> {
|
||||||
|
single: usize,
|
||||||
|
#[field(name = "SomeCase")]
|
||||||
|
#[field(name = "some_case")]
|
||||||
|
some_case: &'r str,
|
||||||
|
}
|
||||||
|
|
||||||
|
let form_string = &["single=123", "some_case=hi_im_here"].join("&");
|
||||||
|
let form: Option<MultiName> = strict(&form_string).ok();
|
||||||
|
assert_eq!(form, Some(MultiName { single: 123, some_case: "hi_im_here", }));
|
||||||
|
|
||||||
|
let form_string = &["single=123", "SomeCase=HiImHere"].join("&");
|
||||||
|
let form: Option<MultiName> = strict(&form_string).ok();
|
||||||
|
assert_eq!(form, Some(MultiName { single: 123, some_case: "HiImHere", }));
|
||||||
|
|
||||||
|
let form_string = &["single=123", "some_case=hi_im_here", "SomeCase=HiImHere"].join("&");
|
||||||
|
let form: Option<MultiName> = strict(&form_string).ok();
|
||||||
|
assert!(form.is_none());
|
||||||
|
|
||||||
|
let form_string = &["single=123", "some_case=hi_im_here", "SomeCase=HiImHere"].join("&");
|
||||||
|
let form: Option<MultiName> = lenient(&form_string).ok();
|
||||||
|
assert_eq!(form, Some(MultiName { single: 123, some_case: "hi_im_here", }));
|
||||||
|
|
||||||
|
let form_string = &["single=123", "SomeCase=HiImHere", "some_case=hi_im_here"].join("&");
|
||||||
|
let form: Option<MultiName> = lenient(&form_string).ok();
|
||||||
|
assert_eq!(form, Some(MultiName { single: 123, some_case: "HiImHere", }));
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, FromForm)]
|
||||||
|
struct CaseInsensitive<'r> {
|
||||||
|
#[field(name = uncased("SomeCase"))]
|
||||||
|
#[field(name = "some_case")]
|
||||||
|
some_case: &'r str,
|
||||||
|
|
||||||
|
#[field(name = uncased("hello"))]
|
||||||
|
hello: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
let form_string = &["HeLLO=123", "sOMECASe=hi_im_here"].join("&");
|
||||||
|
let form: Option<CaseInsensitive> = strict(&form_string).ok();
|
||||||
|
assert_eq!(form, Some(CaseInsensitive { hello: 123, some_case: "hi_im_here", }));
|
||||||
|
|
||||||
|
let form_string = &["hello=456", "SomeCase=HiImHere"].join("&");
|
||||||
|
let form: Option<CaseInsensitive> = strict(&form_string).ok();
|
||||||
|
assert_eq!(form, Some(CaseInsensitive { hello: 456, some_case: "HiImHere", }));
|
||||||
|
|
||||||
|
let form_string = &["helLO=789", "some_case=hi_there"].join("&");
|
||||||
|
let form: Option<CaseInsensitive> = strict(&form_string).ok();
|
||||||
|
assert_eq!(form, Some(CaseInsensitive { hello: 789, some_case: "hi_there", }));
|
||||||
|
|
||||||
|
let form_string = &["hello=123", "SOme_case=hi_im_here"].join("&");
|
||||||
|
let form: Option<CaseInsensitive> = strict(&form_string).ok();
|
||||||
|
assert!(form.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -77,18 +77,23 @@ note: error occurred while deriving `FromForm`
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field
|
error: field name conflicts with previous name
|
||||||
--> $DIR/from_form.rs:33:5
|
--> $DIR/from_form.rs:33:5
|
||||||
|
|
|
|
||||||
33 | foo: usize,
|
33 | foo: usize,
|
||||||
| ^^^^^^^^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
note: previously defined here
|
note: previous field with conflicting name
|
||||||
--> $DIR/from_form.rs:31:5
|
--> $DIR/from_form.rs:31:5
|
||||||
|
|
|
|
||||||
31 | / #[field(name = "foo")]
|
31 | / #[field(name = "foo")]
|
||||||
32 | | field: String,
|
32 | | field: String,
|
||||||
| |_________________^
|
| |_________________^
|
||||||
|
help: field name is part of this field
|
||||||
|
--> $DIR/from_form.rs:33:5
|
||||||
|
|
|
||||||
|
33 | foo: usize,
|
||||||
|
| ^^^^^^^^^^
|
||||||
note: error occurred while deriving `FromForm`
|
note: error occurred while deriving `FromForm`
|
||||||
--> $DIR/from_form.rs:29:10
|
--> $DIR/from_form.rs:29:10
|
||||||
|
|
|
|
||||||
|
@ -96,19 +101,24 @@ note: error occurred while deriving `FromForm`
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field
|
error: field name conflicts with previous name
|
||||||
--> $DIR/from_form.rs:40:5
|
--> $DIR/from_form.rs:40:20
|
||||||
|
|
|
|
||||||
40 | / #[field(name = "hello")]
|
40 | #[field(name = "hello")]
|
||||||
41 | | other: String,
|
| ^^^^^^^
|
||||||
| |_________________^
|
|
||||||
|
|
|
|
||||||
note: previously defined here
|
note: previous field with conflicting name
|
||||||
--> $DIR/from_form.rs:38:5
|
--> $DIR/from_form.rs:38:5
|
||||||
|
|
|
|
||||||
38 | / #[field(name = "hello")]
|
38 | / #[field(name = "hello")]
|
||||||
39 | | first: String,
|
39 | | first: String,
|
||||||
| |_________________^
|
| |_________________^
|
||||||
|
help: field name is part of this field
|
||||||
|
--> $DIR/from_form.rs:40:5
|
||||||
|
|
|
||||||
|
40 | / #[field(name = "hello")]
|
||||||
|
41 | | other: String,
|
||||||
|
| |_________________^
|
||||||
note: error occurred while deriving `FromForm`
|
note: error occurred while deriving `FromForm`
|
||||||
--> $DIR/from_form.rs:36:10
|
--> $DIR/from_form.rs:36:10
|
||||||
|
|
|
|
||||||
|
@ -116,18 +126,23 @@ note: error occurred while deriving `FromForm`
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field
|
error: field name conflicts with previous name
|
||||||
|
--> $DIR/from_form.rs:47:20
|
||||||
|
|
|
||||||
|
47 | #[field(name = "first")]
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
note: previous field with conflicting name
|
||||||
|
--> $DIR/from_form.rs:46:5
|
||||||
|
|
|
||||||
|
46 | first: String,
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
help: field name is part of this field
|
||||||
--> $DIR/from_form.rs:47:5
|
--> $DIR/from_form.rs:47:5
|
||||||
|
|
|
|
||||||
47 | / #[field(name = "first")]
|
47 | / #[field(name = "first")]
|
||||||
48 | | other: String,
|
48 | | other: String,
|
||||||
| |_________________^
|
| |_________________^
|
||||||
|
|
|
||||||
note: previously defined here
|
|
||||||
--> $DIR/from_form.rs:46:5
|
|
||||||
|
|
|
||||||
46 | first: String,
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: error occurred while deriving `FromForm`
|
note: error occurred while deriving `FromForm`
|
||||||
--> $DIR/from_form.rs:44:10
|
--> $DIR/from_form.rs:44:10
|
||||||
|
|
|
|
||||||
|
@ -200,13 +215,24 @@ note: error occurred while deriving `FromForm`
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field renaming
|
error: field has conflicting names
|
||||||
|
--> $DIR/from_form.rs:83:5
|
||||||
|
|
|
||||||
|
83 | / #[field(name = "blah")]
|
||||||
|
84 | | #[field(name = "blah")]
|
||||||
|
85 | | my_field: String,
|
||||||
|
| |____________________^
|
||||||
|
|
|
||||||
|
note: this field name...
|
||||||
|
--> $DIR/from_form.rs:83:20
|
||||||
|
|
|
||||||
|
83 | #[field(name = "blah")]
|
||||||
|
| ^^^^^^
|
||||||
|
note: ...conflicts with this name
|
||||||
--> $DIR/from_form.rs:84:20
|
--> $DIR/from_form.rs:84:20
|
||||||
|
|
|
|
||||||
84 | #[field(name = "blah")]
|
84 | #[field(name = "blah")]
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
||||||
= help: a field can only be renamed once
|
|
||||||
note: error occurred while deriving `FromForm`
|
note: error occurred while deriving `FromForm`
|
||||||
--> $DIR/from_form.rs:81:10
|
--> $DIR/from_form.rs:81:10
|
||||||
|
|
|
|
||||||
|
@ -214,7 +240,7 @@ note: error occurred while deriving `FromForm`
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: invalid value: expected string literal
|
error: expected list `#[attr(..)]`, found bare boolean literal
|
||||||
--> $DIR/from_form.rs:90:20
|
--> $DIR/from_form.rs:90:20
|
||||||
|
|
|
|
||||||
90 | #[field(name = true)]
|
90 | #[field(name = true)]
|
||||||
|
@ -227,7 +253,7 @@ note: error occurred while deriving `FromForm`
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: expected literal, found bare path "name"
|
error: expected expression, found bare path "name"
|
||||||
--> $DIR/from_form.rs:96:13
|
--> $DIR/from_form.rs:96:13
|
||||||
|
|
|
|
||||||
96 | #[field(name)]
|
96 | #[field(name)]
|
||||||
|
@ -240,7 +266,7 @@ note: error occurred while deriving `FromForm`
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: invalid value: expected string literal
|
error: expected list `#[attr(..)]`, found bare integer literal
|
||||||
--> $DIR/from_form.rs:102:20
|
--> $DIR/from_form.rs:102:20
|
||||||
|
|
|
|
||||||
102 | #[field(name = 123)]
|
102 | #[field(name = 123)]
|
||||||
|
|
|
@ -103,3 +103,101 @@ note: error occurred while deriving `FromFormField`
|
||||||
33 | #[derive(FromFormField)]
|
33 | #[derive(FromFormField)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field has conflicting names
|
||||||
|
--> $DIR/from_form_field.rs:41:5
|
||||||
|
|
|
||||||
|
41 | / #[field(name = "foo")]
|
||||||
|
42 | | #[field(name = uncased("FOO"))]
|
||||||
|
43 | | single: usize,
|
||||||
|
| |_________________^
|
||||||
|
|
|
||||||
|
note: this field name...
|
||||||
|
--> $DIR/from_form_field.rs:41:20
|
||||||
|
|
|
||||||
|
41 | #[field(name = "foo")]
|
||||||
|
| ^^^^^
|
||||||
|
note: ...conflicts with this name
|
||||||
|
--> $DIR/from_form_field.rs:42:28
|
||||||
|
|
|
||||||
|
42 | #[field(name = uncased("FOO"))]
|
||||||
|
| ^^^^^
|
||||||
|
note: error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:39:10
|
||||||
|
|
|
||||||
|
39 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field name conflicts with previous name
|
||||||
|
--> $DIR/from_form_field.rs:50:20
|
||||||
|
|
|
||||||
|
50 | #[field(name = "foo")]
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
note: previous field with conflicting name
|
||||||
|
--> $DIR/from_form_field.rs:48:5
|
||||||
|
|
|
||||||
|
48 | / #[field(name = "foo")]
|
||||||
|
49 | | single: usize,
|
||||||
|
| |_________________^
|
||||||
|
help: field name is part of this field
|
||||||
|
--> $DIR/from_form_field.rs:50:5
|
||||||
|
|
|
||||||
|
50 | / #[field(name = "foo")]
|
||||||
|
51 | | other: usize,
|
||||||
|
| |________________^
|
||||||
|
note: error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:46:10
|
||||||
|
|
|
||||||
|
46 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field name conflicts with previous name
|
||||||
|
--> $DIR/from_form_field.rs:58:5
|
||||||
|
|
|
||||||
|
58 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: previous field with conflicting name
|
||||||
|
--> $DIR/from_form_field.rs:56:5
|
||||||
|
|
|
||||||
|
56 | / #[field(name = uncased("HELLO_THERE"))]
|
||||||
|
57 | | single: usize,
|
||||||
|
| |_________________^
|
||||||
|
help: field name is part of this field
|
||||||
|
--> $DIR/from_form_field.rs:58:5
|
||||||
|
|
|
||||||
|
58 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
note: error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:54:10
|
||||||
|
|
|
||||||
|
54 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field name conflicts with previous name
|
||||||
|
--> $DIR/from_form_field.rs:65:5
|
||||||
|
|
|
||||||
|
65 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: previous field with conflicting name
|
||||||
|
--> $DIR/from_form_field.rs:63:5
|
||||||
|
|
|
||||||
|
63 | / #[field(name = "hello_there")]
|
||||||
|
64 | | single: usize,
|
||||||
|
| |_________________^
|
||||||
|
help: field name is part of this field
|
||||||
|
--> $DIR/from_form_field.rs:65:5
|
||||||
|
|
|
||||||
|
65 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
note: error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:61:10
|
||||||
|
|
|
||||||
|
61 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
|
@ -63,7 +63,7 @@ note: error occurred while deriving `UriDisplay`
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: invalid value: expected string literal
|
error: expected list `#[attr(..)]`, found bare integer literal
|
||||||
--> $DIR/uri_display.rs:22:20
|
--> $DIR/uri_display.rs:22:20
|
||||||
|
|
|
|
||||||
22 | #[field(name = 123)]
|
22 | #[field(name = 123)]
|
||||||
|
|
|
@ -83,18 +83,24 @@ error: [note] error occurred while deriving `FromForm`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field
|
error: field name conflicts with previous name
|
||||||
--> $DIR/from_form.rs:33:5
|
--> $DIR/from_form.rs:33:5
|
||||||
|
|
|
|
||||||
33 | foo: usize,
|
33 | foo: usize,
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: [note] previously defined here
|
error: [note] previous field with conflicting name
|
||||||
--> $DIR/from_form.rs:31:5
|
--> $DIR/from_form.rs:31:5
|
||||||
|
|
|
|
||||||
31 | #[field(name = "foo")]
|
31 | #[field(name = "foo")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: [help] field name is part of this field
|
||||||
|
--> $DIR/from_form.rs:33:5
|
||||||
|
|
|
||||||
|
33 | foo: usize,
|
||||||
|
| ^^^
|
||||||
|
|
||||||
error: [note] error occurred while deriving `FromForm`
|
error: [note] error occurred while deriving `FromForm`
|
||||||
--> $DIR/from_form.rs:29:10
|
--> $DIR/from_form.rs:29:10
|
||||||
|
|
|
|
||||||
|
@ -103,18 +109,24 @@ error: [note] error occurred while deriving `FromForm`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field
|
error: field name conflicts with previous name
|
||||||
--> $DIR/from_form.rs:40:5
|
--> $DIR/from_form.rs:40:20
|
||||||
|
|
|
|
||||||
40 | #[field(name = "hello")]
|
40 | #[field(name = "hello")]
|
||||||
| ^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: [note] previously defined here
|
error: [note] previous field with conflicting name
|
||||||
--> $DIR/from_form.rs:38:5
|
--> $DIR/from_form.rs:38:5
|
||||||
|
|
|
|
||||||
38 | #[field(name = "hello")]
|
38 | #[field(name = "hello")]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: [help] field name is part of this field
|
||||||
|
--> $DIR/from_form.rs:40:5
|
||||||
|
|
|
||||||
|
40 | #[field(name = "hello")]
|
||||||
|
| ^
|
||||||
|
|
||||||
error: [note] error occurred while deriving `FromForm`
|
error: [note] error occurred while deriving `FromForm`
|
||||||
--> $DIR/from_form.rs:36:10
|
--> $DIR/from_form.rs:36:10
|
||||||
|
|
|
|
||||||
|
@ -123,18 +135,24 @@ error: [note] error occurred while deriving `FromForm`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field
|
error: field name conflicts with previous name
|
||||||
--> $DIR/from_form.rs:47:5
|
--> $DIR/from_form.rs:47:20
|
||||||
|
|
|
|
||||||
47 | #[field(name = "first")]
|
47 | #[field(name = "first")]
|
||||||
| ^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: [note] previously defined here
|
error: [note] previous field with conflicting name
|
||||||
--> $DIR/from_form.rs:46:5
|
--> $DIR/from_form.rs:46:5
|
||||||
|
|
|
|
||||||
46 | first: String,
|
46 | first: String,
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
|
error: [help] field name is part of this field
|
||||||
|
--> $DIR/from_form.rs:47:5
|
||||||
|
|
|
||||||
|
47 | #[field(name = "first")]
|
||||||
|
| ^
|
||||||
|
|
||||||
error: [note] error occurred while deriving `FromForm`
|
error: [note] error occurred while deriving `FromForm`
|
||||||
--> $DIR/from_form.rs:44:10
|
--> $DIR/from_form.rs:44:10
|
||||||
|
|
|
|
||||||
|
@ -213,8 +231,19 @@ error: [note] error occurred while deriving `FromForm`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: duplicate form field renaming
|
error: field has conflicting names
|
||||||
--- help: a field can only be renamed once
|
--> $DIR/from_form.rs:83:5
|
||||||
|
|
|
||||||
|
83 | #[field(name = "blah")]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: [note] this field name...
|
||||||
|
--> $DIR/from_form.rs:83:20
|
||||||
|
|
|
||||||
|
83 | #[field(name = "blah")]
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: [note] ...conflicts with this name
|
||||||
--> $DIR/from_form.rs:84:20
|
--> $DIR/from_form.rs:84:20
|
||||||
|
|
|
|
||||||
84 | #[field(name = "blah")]
|
84 | #[field(name = "blah")]
|
||||||
|
@ -228,7 +257,7 @@ error: [note] error occurred while deriving `FromForm`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: invalid value: expected string literal
|
error: expected list `#[attr(..)]`, found bare boolean literal
|
||||||
--> $DIR/from_form.rs:90:20
|
--> $DIR/from_form.rs:90:20
|
||||||
|
|
|
|
||||||
90 | #[field(name = true)]
|
90 | #[field(name = true)]
|
||||||
|
@ -242,7 +271,7 @@ error: [note] error occurred while deriving `FromForm`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: expected literal, found bare path "name"
|
error: expected expression, found bare path "name"
|
||||||
--> $DIR/from_form.rs:96:13
|
--> $DIR/from_form.rs:96:13
|
||||||
|
|
|
|
||||||
96 | #[field(name)]
|
96 | #[field(name)]
|
||||||
|
@ -256,7 +285,7 @@ error: [note] error occurred while deriving `FromForm`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: invalid value: expected string literal
|
error: expected list `#[attr(..)]`, found bare integer literal
|
||||||
--> $DIR/from_form.rs:102:20
|
--> $DIR/from_form.rs:102:20
|
||||||
|
|
|
|
||||||
102 | #[field(name = 123)]
|
102 | #[field(name = 123)]
|
||||||
|
|
|
@ -109,3 +109,107 @@ error: [note] error occurred while deriving `FromFormField`
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field has conflicting names
|
||||||
|
--> $DIR/from_form_field.rs:41:5
|
||||||
|
|
|
||||||
|
41 | #[field(name = "foo")]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: [note] this field name...
|
||||||
|
--> $DIR/from_form_field.rs:41:20
|
||||||
|
|
|
||||||
|
41 | #[field(name = "foo")]
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: [note] ...conflicts with this name
|
||||||
|
--> $DIR/from_form_field.rs:42:28
|
||||||
|
|
|
||||||
|
42 | #[field(name = uncased("FOO"))]
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: [note] error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:39:10
|
||||||
|
|
|
||||||
|
39 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field name conflicts with previous name
|
||||||
|
--> $DIR/from_form_field.rs:50:20
|
||||||
|
|
|
||||||
|
50 | #[field(name = "foo")]
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: [note] previous field with conflicting name
|
||||||
|
--> $DIR/from_form_field.rs:48:5
|
||||||
|
|
|
||||||
|
48 | #[field(name = "foo")]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: [help] field name is part of this field
|
||||||
|
--> $DIR/from_form_field.rs:50:5
|
||||||
|
|
|
||||||
|
50 | #[field(name = "foo")]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: [note] error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:46:10
|
||||||
|
|
|
||||||
|
46 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field name conflicts with previous name
|
||||||
|
--> $DIR/from_form_field.rs:58:5
|
||||||
|
|
|
||||||
|
58 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: [note] previous field with conflicting name
|
||||||
|
--> $DIR/from_form_field.rs:56:5
|
||||||
|
|
|
||||||
|
56 | #[field(name = uncased("HELLO_THERE"))]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: [help] field name is part of this field
|
||||||
|
--> $DIR/from_form_field.rs:58:5
|
||||||
|
|
|
||||||
|
58 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: [note] error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:54:10
|
||||||
|
|
|
||||||
|
54 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: field name conflicts with previous name
|
||||||
|
--> $DIR/from_form_field.rs:65:5
|
||||||
|
|
|
||||||
|
65 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: [note] previous field with conflicting name
|
||||||
|
--> $DIR/from_form_field.rs:63:5
|
||||||
|
|
|
||||||
|
63 | #[field(name = "hello_there")]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: [help] field name is part of this field
|
||||||
|
--> $DIR/from_form_field.rs:65:5
|
||||||
|
|
|
||||||
|
65 | hello_there: usize,
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: [note] error occurred while deriving `FromForm`
|
||||||
|
--> $DIR/from_form_field.rs:61:10
|
||||||
|
|
|
||||||
|
61 | #[derive(FromForm)]
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
|
@ -68,7 +68,7 @@ error: [note] error occurred while deriving `UriDisplay`
|
||||||
|
|
|
|
||||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: invalid value: expected string literal
|
error: expected list `#[attr(..)]`, found bare integer literal
|
||||||
--> $DIR/uri_display.rs:22:20
|
--> $DIR/uri_display.rs:22:20
|
||||||
|
|
|
|
||||||
22 | #[field(name = 123)]
|
22 | #[field(name = 123)]
|
||||||
|
|
|
@ -36,4 +36,33 @@ enum Bar2 {
|
||||||
A,
|
A,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct Renamed0 {
|
||||||
|
#[field(name = "foo")]
|
||||||
|
#[field(name = uncased("FOO"))]
|
||||||
|
single: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct Renamed1 {
|
||||||
|
#[field(name = "foo")]
|
||||||
|
single: usize,
|
||||||
|
#[field(name = "foo")]
|
||||||
|
other: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct Renamed2 {
|
||||||
|
#[field(name = uncased("HELLO_THERE"))]
|
||||||
|
single: usize,
|
||||||
|
hello_there: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct Renamed3 {
|
||||||
|
#[field(name = "hello_there")]
|
||||||
|
single: usize,
|
||||||
|
hello_there: usize,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -764,16 +764,17 @@ By default, Rocket matches the name of an incoming form field to the name of a
|
||||||
structure field. While this behavior is typical, it may also be desired to use
|
structure field. While this behavior is typical, it may also be desired to use
|
||||||
different names for form fields and struct fields while still parsing as
|
different names for form fields and struct fields while still parsing as
|
||||||
expected. You can ask Rocket to look for a different form field for a given
|
expected. You can ask Rocket to look for a different form field for a given
|
||||||
structure field by using the `#[field(name = "name")]` field annotation.
|
structure field by using one or more `#[field(name = "name")]` or `#[field(name
|
||||||
|
= uncased("name")]` field annotation. The `uncased` variant case-insensitively
|
||||||
|
matches field names.
|
||||||
|
|
||||||
As an example, say that you're writing an application that receives data from an
|
As an example, say that you're writing an application that receives data from an
|
||||||
external service. The external service `POST`s a form with a field named
|
external service. The external service `POST`s a form with a field named
|
||||||
`first-Name` which you'd like to write as `first_name` in Rust. Field renaming
|
`first-Name` which you'd like to write as `first_name` in Rust. Such a form
|
||||||
helps:
|
structure can be written as:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #[macro_use] extern crate rocket;
|
# use rocket::form::FromForm;
|
||||||
# fn main() {}
|
|
||||||
|
|
||||||
#[derive(FromForm)]
|
#[derive(FromForm)]
|
||||||
struct External {
|
struct External {
|
||||||
|
@ -782,8 +783,41 @@ struct External {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Rocket will then match the form field named `first-Name` to the structure field
|
If you want to accept both `firstName` case-insensitively as well as
|
||||||
named `first_name`.
|
`first_name` case-sensitively, you'll need to use two annotations:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# use rocket::form::FromForm;
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct External {
|
||||||
|
#[field(name = uncased("firstName"))]
|
||||||
|
#[field(name = "first_name")]
|
||||||
|
first_name: String
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will match any casing of `firstName` including `FirstName`, `firstname`,
|
||||||
|
`FIRSTname`, and so on, but only match exactly on `first_name`.
|
||||||
|
|
||||||
|
If instead you wanted to match any of `first-name`, `first_name` or `firstName`,
|
||||||
|
in each instance case-insensitively, you would write:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# use rocket::form::FromForm;
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct External {
|
||||||
|
#[field(name = uncased("first-name"))]
|
||||||
|
#[field(name = uncased("first_name"))]
|
||||||
|
#[field(name = uncased("firstname"))]
|
||||||
|
first_name: String
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Cased and uncased renamings can be mixed and matched, and any number of
|
||||||
|
renamings is allowed. Rocket will emit an error at compile-time if field names
|
||||||
|
conflict, preventing ambiguous parsing at runtime.
|
||||||
|
|
||||||
### Ad-Hoc Validation
|
### Ad-Hoc Validation
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue