mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
xso: refine handling of multiple #[xml(text)]
fields
Previously, we only enforced the existence of at most one `#[xml(text)]` field only at code generation time for `FromXml`. This change enforces it at parsing time, which is more consistent and allows for a clearer error message.
This commit is contained in:
parent
ae30221e3c
commit
46584f05f9
3 changed files with 34 additions and 7 deletions
|
@ -8,7 +8,7 @@
|
|||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::*;
|
||||
use syn::{spanned::Spanned, *};
|
||||
|
||||
use crate::error_message::ParentRef;
|
||||
use crate::field::{FieldBuilderPart, FieldDef, FieldIteratorPart, FieldTempInit};
|
||||
|
@ -26,6 +26,7 @@ impl Compound {
|
|||
/// Construct a compound from fields.
|
||||
pub(crate) fn from_fields(compound_fields: &Fields) -> Result<Self> {
|
||||
let mut fields = Vec::with_capacity(compound_fields.len());
|
||||
let mut text_field = None;
|
||||
for (i, field) in compound_fields.iter().enumerate() {
|
||||
let index = match i.try_into() {
|
||||
Ok(v) => v,
|
||||
|
@ -38,7 +39,24 @@ impl Compound {
|
|||
))
|
||||
}
|
||||
};
|
||||
fields.push(FieldDef::from_field(field, index)?);
|
||||
let field = FieldDef::from_field(field, index)?;
|
||||
|
||||
if field.is_text_field() {
|
||||
if let Some(other_field) = text_field.as_ref() {
|
||||
let mut err = Error::new_spanned(
|
||||
field.member(),
|
||||
"only one `#[xml(text)]` field allowed per compound",
|
||||
);
|
||||
err.combine(Error::new(
|
||||
*other_field,
|
||||
"the other `#[xml(text)]` field is here",
|
||||
));
|
||||
return Err(err);
|
||||
}
|
||||
text_field = Some(field.member().span())
|
||||
}
|
||||
|
||||
fields.push(field);
|
||||
}
|
||||
|
||||
Ok(Self { fields })
|
||||
|
@ -104,10 +122,9 @@ impl Compound {
|
|||
finalize,
|
||||
} => {
|
||||
if text_handler.is_some() {
|
||||
return Err(Error::new_spanned(
|
||||
field.member(),
|
||||
"more than one field attempts to collect text data",
|
||||
));
|
||||
// the existence of only one text handler is enforced
|
||||
// by Compound's constructor(s).
|
||||
panic!("more than one field attempts to collect text data");
|
||||
}
|
||||
|
||||
builder_data_def.extend(quote! {
|
||||
|
|
|
@ -329,4 +329,12 @@ impl FieldDef {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if this field's parsing consumes text data.
|
||||
pub(crate) fn is_text_field(&self) -> bool {
|
||||
match self.kind {
|
||||
FieldKind::Text { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,9 @@ The `text` meta causes the field to be mapped to the text content of the
|
|||
element. For `FromXml`, the field's type must implement [`FromXmlText`] and
|
||||
for `IntoXml`, the field's type must implement [`IntoXmlText`].
|
||||
|
||||
The `text` meta supports no options or value.
|
||||
The `text` meta supports no options or value. Only a single field per struct
|
||||
may be annotated with `#[xml(text)]` at a time, to avoid parsing ambiguities.
|
||||
This is also true if only `IntoXml` is derived on a field, for consistency.
|
||||
|
||||
##### Example
|
||||
|
||||
|
|
Loading…
Reference in a new issue