xso-proc: deduplicate parsing of namespace / name keys
This commit is contained in:
parent
6440209f95
commit
e0de035448
4 changed files with 88 additions and 76 deletions
|
|
@ -15,7 +15,7 @@ use syn::*;
|
||||||
use crate::common::{AsXmlParts, FromXmlParts, ItemDef};
|
use crate::common::{AsXmlParts, FromXmlParts, ItemDef};
|
||||||
use crate::compound::Compound;
|
use crate::compound::Compound;
|
||||||
use crate::error_message::ParentRef;
|
use crate::error_message::ParentRef;
|
||||||
use crate::meta::{reject_key, Flag, NameRef, NamespaceRef, XmlCompoundMeta};
|
use crate::meta::{reject_key, Flag, NameRef, NamespaceRef, QNameRef, XmlCompoundMeta};
|
||||||
use crate::state::{AsItemsStateMachine, FromEventsStateMachine};
|
use crate::state::{AsItemsStateMachine, FromEventsStateMachine};
|
||||||
|
|
||||||
/// The definition of an enum variant, switched on the XML element's name.
|
/// The definition of an enum variant, switched on the XML element's name.
|
||||||
|
|
@ -38,8 +38,7 @@ impl NameVariant {
|
||||||
// an error if they are present.
|
// an error if they are present.
|
||||||
let XmlCompoundMeta {
|
let XmlCompoundMeta {
|
||||||
span: meta_span,
|
span: meta_span,
|
||||||
namespace,
|
qname: QNameRef { namespace, name },
|
||||||
name,
|
|
||||||
exhaustive,
|
exhaustive,
|
||||||
debug,
|
debug,
|
||||||
builder,
|
builder,
|
||||||
|
|
@ -172,8 +171,7 @@ impl EnumDef {
|
||||||
// an error if they are present.
|
// an error if they are present.
|
||||||
let XmlCompoundMeta {
|
let XmlCompoundMeta {
|
||||||
span: meta_span,
|
span: meta_span,
|
||||||
namespace,
|
qname: QNameRef { namespace, name },
|
||||||
name,
|
|
||||||
exhaustive,
|
exhaustive,
|
||||||
debug,
|
debug,
|
||||||
builder,
|
builder,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use syn::{spanned::Spanned, *};
|
||||||
use rxml_validation::NcName;
|
use rxml_validation::NcName;
|
||||||
|
|
||||||
use crate::error_message::{self, ParentRef};
|
use crate::error_message::{self, ParentRef};
|
||||||
use crate::meta::{AmountConstraint, Flag, NameRef, NamespaceRef, XmlFieldMeta};
|
use crate::meta::{AmountConstraint, Flag, NameRef, NamespaceRef, QNameRef, XmlFieldMeta};
|
||||||
use crate::scope::{AsItemsScope, FromEventsScope};
|
use crate::scope::{AsItemsScope, FromEventsScope};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
as_optional_xml_text_fn, as_xml_iter_fn, as_xml_text_fn, default_fn, extend_fn, from_events_fn,
|
as_optional_xml_text_fn, as_xml_iter_fn, as_xml_text_fn, default_fn, extend_fn, from_events_fn,
|
||||||
|
|
@ -172,8 +172,7 @@ impl FieldKind {
|
||||||
match meta {
|
match meta {
|
||||||
XmlFieldMeta::Attribute {
|
XmlFieldMeta::Attribute {
|
||||||
span,
|
span,
|
||||||
namespace,
|
qname: QNameRef { namespace, name },
|
||||||
name,
|
|
||||||
default_,
|
default_,
|
||||||
} => {
|
} => {
|
||||||
let xml_name = match name {
|
let xml_name = match name {
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,63 @@ impl<T: Spanned> From<T> for Flag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A pair of `namespace` and `name` keys.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub(crate) struct QNameRef {
|
||||||
|
/// The XML namespace supplied.
|
||||||
|
pub(crate) namespace: Option<NamespaceRef>,
|
||||||
|
|
||||||
|
/// The XML name supplied.
|
||||||
|
pub(crate) name: Option<NameRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QNameRef {
|
||||||
|
/// Attempt to incrementally parse this QNameRef.
|
||||||
|
///
|
||||||
|
/// If `meta` contains either `namespace` or `name` keys, they are
|
||||||
|
/// processed and either `Ok(None)` or an error is returned.
|
||||||
|
///
|
||||||
|
/// If no matching key is found, `Ok(Some(meta))` is returned for further
|
||||||
|
/// processing.
|
||||||
|
fn parse_incremental_from_meta<'x>(
|
||||||
|
&mut self,
|
||||||
|
meta: ParseNestedMeta<'x>,
|
||||||
|
) -> Result<Option<ParseNestedMeta<'x>>> {
|
||||||
|
if meta.path.is_ident("name") {
|
||||||
|
if self.name.is_some() {
|
||||||
|
return Err(Error::new_spanned(meta.path, "duplicate `name` key"));
|
||||||
|
}
|
||||||
|
let value = meta.value()?;
|
||||||
|
let name_span = value.span();
|
||||||
|
let (new_namespace, new_name) = parse_prefixed_name(value)?;
|
||||||
|
if let Some(new_namespace) = new_namespace {
|
||||||
|
if let Some(namespace) = self.namespace.as_ref() {
|
||||||
|
let mut error = Error::new(
|
||||||
|
name_span,
|
||||||
|
"cannot combine `namespace` key with prefixed `name`",
|
||||||
|
);
|
||||||
|
error.combine(Error::new_spanned(namespace, "`namespace` was set here"));
|
||||||
|
return Err(error);
|
||||||
|
}
|
||||||
|
self.namespace = Some(new_namespace);
|
||||||
|
}
|
||||||
|
self.name = Some(new_name);
|
||||||
|
Ok(None)
|
||||||
|
} else if meta.path.is_ident("namespace") {
|
||||||
|
if self.namespace.is_some() {
|
||||||
|
return Err(Error::new_spanned(
|
||||||
|
meta.path,
|
||||||
|
"duplicate `namespace` key or `name` key has prefix",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
self.namespace = Some(meta.value()?.parse()?);
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(meta))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Contents of an `#[xml(..)]` attribute on a struct, enum variant, or enum.
|
/// Contents of an `#[xml(..)]` attribute on a struct, enum variant, or enum.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct XmlCompoundMeta {
|
pub(crate) struct XmlCompoundMeta {
|
||||||
|
|
@ -268,11 +325,9 @@ pub(crate) struct XmlCompoundMeta {
|
||||||
/// This is useful for error messages.
|
/// This is useful for error messages.
|
||||||
pub(crate) span: Span,
|
pub(crate) span: Span,
|
||||||
|
|
||||||
/// The value assigned to `namespace` inside `#[xml(..)]`, if any.
|
/// The value assigned to `namespace` and `name` fields inside
|
||||||
pub(crate) namespace: Option<NamespaceRef>,
|
/// `#[xml(..)]`, if any.
|
||||||
|
pub(crate) qname: QNameRef,
|
||||||
/// The value assigned to `name` inside `#[xml(..)]`, if any.
|
|
||||||
pub(crate) name: Option<NameRef>,
|
|
||||||
|
|
||||||
/// The debug flag.
|
/// The debug flag.
|
||||||
pub(crate) debug: Flag,
|
pub(crate) debug: Flag,
|
||||||
|
|
@ -293,27 +348,14 @@ impl XmlCompoundMeta {
|
||||||
/// Undefined options or options with incompatible values are rejected
|
/// Undefined options or options with incompatible values are rejected
|
||||||
/// with an appropriate compile-time error.
|
/// with an appropriate compile-time error.
|
||||||
fn parse_from_attribute(attr: &Attribute) -> Result<Self> {
|
fn parse_from_attribute(attr: &Attribute) -> Result<Self> {
|
||||||
let mut namespace = None;
|
let mut qname = QNameRef::default();
|
||||||
let mut name = None;
|
|
||||||
let mut builder = None;
|
let mut builder = None;
|
||||||
let mut iterator = None;
|
let mut iterator = None;
|
||||||
let mut debug = Flag::Absent;
|
let mut debug = Flag::Absent;
|
||||||
let mut exhaustive = Flag::Absent;
|
let mut exhaustive = Flag::Absent;
|
||||||
|
|
||||||
attr.parse_nested_meta(|meta| {
|
attr.parse_nested_meta(|meta| {
|
||||||
if meta.path.is_ident("name") {
|
if meta.path.is_ident("debug") {
|
||||||
if name.is_some() {
|
|
||||||
return Err(Error::new_spanned(meta.path, "duplicate `name` key"));
|
|
||||||
}
|
|
||||||
name = Some(meta.value()?.parse()?);
|
|
||||||
Ok(())
|
|
||||||
} else if meta.path.is_ident("namespace") {
|
|
||||||
if namespace.is_some() {
|
|
||||||
return Err(Error::new_spanned(meta.path, "duplicate `namespace` key"));
|
|
||||||
}
|
|
||||||
namespace = Some(meta.value()?.parse()?);
|
|
||||||
Ok(())
|
|
||||||
} else if meta.path.is_ident("debug") {
|
|
||||||
if debug.is_set() {
|
if debug.is_set() {
|
||||||
return Err(Error::new_spanned(meta.path, "duplicate `debug` key"));
|
return Err(Error::new_spanned(meta.path, "duplicate `debug` key"));
|
||||||
}
|
}
|
||||||
|
|
@ -338,14 +380,16 @@ impl XmlCompoundMeta {
|
||||||
exhaustive = (&meta.path).into();
|
exhaustive = (&meta.path).into();
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new_spanned(meta.path, "unsupported key"))
|
match qname.parse_incremental_from_meta(meta)? {
|
||||||
|
None => Ok(()),
|
||||||
|
Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
span: attr.span(),
|
span: attr.span(),
|
||||||
namespace,
|
qname,
|
||||||
name,
|
|
||||||
debug,
|
debug,
|
||||||
builder,
|
builder,
|
||||||
iterator,
|
iterator,
|
||||||
|
|
@ -585,11 +629,8 @@ pub(crate) enum XmlFieldMeta {
|
||||||
/// This is useful for error messages.
|
/// This is useful for error messages.
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
||||||
/// The XML namespace supplied.
|
/// The namespace/name keys.
|
||||||
namespace: Option<NamespaceRef>,
|
qname: QNameRef,
|
||||||
|
|
||||||
/// The XML name supplied.
|
|
||||||
name: Option<NameRef>,
|
|
||||||
|
|
||||||
/// The `default` flag.
|
/// The `default` flag.
|
||||||
default_: Flag,
|
default_: Flag,
|
||||||
|
|
@ -624,65 +665,40 @@ impl XmlFieldMeta {
|
||||||
let (namespace, name) = parse_prefixed_name(meta.value()?)?;
|
let (namespace, name) = parse_prefixed_name(meta.value()?)?;
|
||||||
Ok(Self::Attribute {
|
Ok(Self::Attribute {
|
||||||
span: meta.path.span(),
|
span: meta.path.span(),
|
||||||
|
qname: QNameRef {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
namespace,
|
namespace,
|
||||||
|
},
|
||||||
default_: Flag::Absent,
|
default_: Flag::Absent,
|
||||||
})
|
})
|
||||||
} else if meta.input.peek(syn::token::Paren) {
|
} else if meta.input.peek(syn::token::Paren) {
|
||||||
// full syntax
|
// full syntax
|
||||||
let mut name: Option<NameRef> = None;
|
let mut qname = QNameRef::default();
|
||||||
let mut namespace: Option<NamespaceRef> = None;
|
|
||||||
let mut default_ = Flag::Absent;
|
let mut default_ = Flag::Absent;
|
||||||
meta.parse_nested_meta(|meta| {
|
meta.parse_nested_meta(|meta| {
|
||||||
if meta.path.is_ident("name") {
|
if meta.path.is_ident("default") {
|
||||||
if name.is_some() {
|
|
||||||
return Err(Error::new_spanned(meta.path, "duplicate `name` key"));
|
|
||||||
}
|
|
||||||
let value = meta.value()?;
|
|
||||||
let name_span = value.span();
|
|
||||||
let (new_namespace, new_name) = parse_prefixed_name(value)?;
|
|
||||||
if let Some(new_namespace) = new_namespace {
|
|
||||||
if namespace.is_some() {
|
|
||||||
return Err(Error::new(
|
|
||||||
name_span,
|
|
||||||
"cannot combine `namespace` key with prefixed `name`",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
namespace = Some(new_namespace);
|
|
||||||
}
|
|
||||||
name = Some(new_name);
|
|
||||||
Ok(())
|
|
||||||
} else if meta.path.is_ident("namespace") {
|
|
||||||
if namespace.is_some() {
|
|
||||||
return Err(Error::new_spanned(
|
|
||||||
meta.path,
|
|
||||||
"duplicate `namespace` key or `name` key has prefix",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
namespace = Some(meta.value()?.parse()?);
|
|
||||||
Ok(())
|
|
||||||
} else if meta.path.is_ident("default") {
|
|
||||||
if default_.is_set() {
|
if default_.is_set() {
|
||||||
return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
|
return Err(Error::new_spanned(meta.path, "duplicate `default` key"));
|
||||||
}
|
}
|
||||||
default_ = (&meta.path).into();
|
default_ = (&meta.path).into();
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new_spanned(meta.path, "unsupported key"))
|
match qname.parse_incremental_from_meta(meta)? {
|
||||||
|
None => Ok(()),
|
||||||
|
Some(meta) => Err(Error::new_spanned(meta.path, "unsupported key")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
Ok(Self::Attribute {
|
Ok(Self::Attribute {
|
||||||
span: meta.path.span(),
|
span: meta.path.span(),
|
||||||
name,
|
qname,
|
||||||
namespace,
|
|
||||||
default_,
|
default_,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// argument-less syntax
|
// argument-less syntax
|
||||||
Ok(Self::Attribute {
|
Ok(Self::Attribute {
|
||||||
span: meta.path.span(),
|
span: meta.path.span(),
|
||||||
name: None,
|
qname: QNameRef::default(),
|
||||||
namespace: None,
|
|
||||||
default_: Flag::Absent,
|
default_: Flag::Absent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use syn::*;
|
||||||
|
|
||||||
use crate::common::{AsXmlParts, FromXmlParts, ItemDef};
|
use crate::common::{AsXmlParts, FromXmlParts, ItemDef};
|
||||||
use crate::compound::Compound;
|
use crate::compound::Compound;
|
||||||
use crate::meta::{reject_key, Flag, NameRef, NamespaceRef, XmlCompoundMeta};
|
use crate::meta::{reject_key, Flag, NameRef, NamespaceRef, QNameRef, XmlCompoundMeta};
|
||||||
|
|
||||||
/// Definition of a struct and how to parse it.
|
/// Definition of a struct and how to parse it.
|
||||||
pub(crate) struct StructDef {
|
pub(crate) struct StructDef {
|
||||||
|
|
@ -46,8 +46,7 @@ impl StructDef {
|
||||||
// an error if they are present.
|
// an error if they are present.
|
||||||
let XmlCompoundMeta {
|
let XmlCompoundMeta {
|
||||||
span: meta_span,
|
span: meta_span,
|
||||||
namespace,
|
qname: QNameRef { namespace, name },
|
||||||
name,
|
|
||||||
exhaustive,
|
exhaustive,
|
||||||
debug,
|
debug,
|
||||||
builder,
|
builder,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue