@@ -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