mirror of https://gitlab.com/xmpp-rs/xmpp-rs.git
xso_proc: allow `#[xml(element)]` without any selector
This commit is contained in:
parent
b0d9f57160
commit
d4bce2e959
|
@ -7,6 +7,7 @@ use syn::*;
|
|||
|
||||
use crate::error_message::{self, ParentRef};
|
||||
use crate::meta::{FlagOr, Name, NameRef, NamespaceRef, StaticNamespace};
|
||||
use crate::structs::ElementSelector;
|
||||
|
||||
use super::FieldParsePart;
|
||||
|
||||
|
@ -16,11 +17,8 @@ use super::FieldParsePart;
|
|||
/// Maps to `#[xml(element)]`.
|
||||
#[cfg_attr(feature = "debug", derive(Debug))]
|
||||
pub(crate) struct ElementField {
|
||||
/// The XML namespace of the child element to collect.
|
||||
namespace: StaticNamespace,
|
||||
|
||||
/// The XML name of the child element to collect.
|
||||
name: Name,
|
||||
/// Logic to select matching child elements.
|
||||
selector: ElementSelector,
|
||||
|
||||
/// If set, the field value will be generated using
|
||||
/// [`std::default::Default`] or the given callable if no matching child
|
||||
|
@ -43,19 +41,14 @@ impl ElementField {
|
|||
/// can be constructed. This should point at the `#[xml(..)]` meta of the
|
||||
/// field or another closely-related object.
|
||||
pub(super) fn new(
|
||||
attr_span: &Span,
|
||||
_attr_span: &Span,
|
||||
namespace: Option<NamespaceRef>,
|
||||
name: Option<NameRef>,
|
||||
default_: FlagOr<Path>,
|
||||
) -> Result<Self> {
|
||||
let namespace = match namespace {
|
||||
None => {
|
||||
return Err(Error::new(
|
||||
attr_span.clone(),
|
||||
"#[xml(element)] requires namespace attribute",
|
||||
))
|
||||
}
|
||||
Some(NamespaceRef::Static(ns)) => ns,
|
||||
None => None,
|
||||
Some(NamespaceRef::Static(ns)) => Some(ns),
|
||||
Some(NamespaceRef::Dyn(ns)) => {
|
||||
return Err(Error::new_spanned(
|
||||
ns,
|
||||
|
@ -69,20 +62,14 @@ impl ElementField {
|
|||
))
|
||||
}
|
||||
};
|
||||
let name = match name {
|
||||
None => {
|
||||
return Err(Error::new(
|
||||
attr_span.clone(),
|
||||
"#[xml(element)] requires name attribute",
|
||||
))
|
||||
}
|
||||
Some(name) => name,
|
||||
let name = name.map(Name::from);
|
||||
let selector = match (namespace, name) {
|
||||
(Some(namespace), Some(name)) => ElementSelector::Qualified { namespace, name },
|
||||
(Some(namespace), None) => ElementSelector::ByNamespace(namespace),
|
||||
(None, Some(name)) => ElementSelector::ByName(name),
|
||||
(None, None) => ElementSelector::Any,
|
||||
};
|
||||
Ok(Self {
|
||||
namespace,
|
||||
name: name.into(),
|
||||
default_,
|
||||
})
|
||||
Ok(Self { selector, default_ })
|
||||
}
|
||||
|
||||
/// Construct the code necessary to parse the child element from a
|
||||
|
@ -107,8 +94,9 @@ impl ElementField {
|
|||
ident: Member,
|
||||
ty: Type,
|
||||
) -> Result<FieldParsePart> {
|
||||
let field_name = self.name;
|
||||
let field_namespace = self.namespace;
|
||||
let test = self
|
||||
.selector
|
||||
.build_test(&Ident::new("residual", Span::call_site()));
|
||||
let missingerr = error_message::on_missing_child(name, &ident);
|
||||
let duperr = error_message::on_duplicate_child(name, &ident);
|
||||
let on_missing = match self.default_ {
|
||||
|
@ -133,7 +121,7 @@ impl ElementField {
|
|||
let mut #tempname: Option<::xso::exports::minidom::Element> = None;
|
||||
},
|
||||
childiter: quote! {
|
||||
residual = if residual.is(#field_name, #field_namespace) {
|
||||
residual = if #test {
|
||||
if #tempname.is_some() {
|
||||
return Err(::xso::error::Error::ParseError(#duperr));
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ impl ElementSelector {
|
|||
/// If the `minidom::Element` in `residual` matches the selector, the
|
||||
/// token stream will evaluate to true. Otherwise, it will evaluate to
|
||||
/// false.
|
||||
fn build_test(self, residual: &Ident) -> TokenStream {
|
||||
pub(crate) fn build_test(self, residual: &Ident) -> TokenStream {
|
||||
match self {
|
||||
Self::Any => quote! { true },
|
||||
Self::ByName(name) => quote! {
|
||||
|
|
|
@ -331,12 +331,13 @@ The following field kinds are available:
|
|||
of the [`FromXmlText`] / [`IntoXmlText`] implementation of the field's
|
||||
type.
|
||||
|
||||
- `element(..)`: Collect a single element as [`minidom::Element`] instead of
|
||||
attempting to destructure it. The field type must implement `From<Element>`
|
||||
and `Into<Option<Element>>` ([`minidom::Element`] implements both).
|
||||
- `element`, `element(..)`: Collect a single element as [`minidom::Element`]
|
||||
instead of attempting to destructure it. The field type must implement
|
||||
`From<Element>` and `Into<Option<Element>>` ([`minidom::Element`] implements
|
||||
both).
|
||||
|
||||
- `name = ..` : The XML name of the element to match.
|
||||
- `namespace = ..`: The XML namespace of the element to match.
|
||||
- `name = ..` (optional): The XML name of the element to match.
|
||||
- `namespace = ..` (optional): The XML namespace of the element to match.
|
||||
- `default`, `default = ..`: If set, a field value is generated if the
|
||||
child is not present instead of failing to parse. If the optional argument
|
||||
is present, it must be the path to a callable which returns the field's
|
||||
|
|
Loading…
Reference in New Issue