use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::*;
use crate::error_message::{self, ParentRef};
use crate::meta::{Name, NameRef, NamespaceRef, StaticNamespace};
use super::{Field, FieldParsePart};
#[derive(Debug)]
pub(crate) struct FlagField {
namespace: StaticNamespace,
name: Name,
}
impl FlagField {
pub(super) fn new(
attr_span: &Span,
namespace: Option<NamespaceRef>,
name: Option<NameRef>,
) -> Result<Self> {
let namespace = match namespace {
None => {
return Err(Error::new(
attr_span.clone(),
"#[xml(flag)] requires namespace attribute",
))
}
Some(NamespaceRef::Static(ns)) => ns,
Some(NamespaceRef::Dyn(ns)) => {
return Err(Error::new_spanned(
ns,
"dynamic namespaces cannot be used with #[xml(flag)]",
))
}
Some(NamespaceRef::Super(ns)) => {
return Err(Error::new_spanned(
ns,
"flag elements cannot refer to the parent namespace",
))
}
};
let name = match name {
None => {
return Err(Error::new(
attr_span.clone(),
"#[xml(flag)] requires name attribute",
))
}
Some(name) => name,
};
Ok(Self {
namespace,
name: name.into(),
})
}
}
impl Field for FlagField {
fn build_try_from_element(
&self,
container_name: &ParentRef,
_container_namespace_expr: &Expr,
tempname: Ident,
member: &Member,
_ty: &Type,
) -> Result<FieldParsePart> {
let field_name = &self.name;
let field_namespace = &self.namespace;
let duperr = error_message::on_duplicate_child(container_name, member);
Ok(FieldParsePart {
tempinit: quote! {
let mut #tempname = false;
},
childiter: quote! {
residual = if residual.is(#field_name, #field_namespace) {
if #tempname {
return Err(::xso::error::Error::ParseError(#duperr));
}
#tempname = true;
continue;
} else {
residual
};
},
value: quote! { #tempname },
..FieldParsePart::default()
})
}
fn build_into_element(
&self,
_container_name: &ParentRef,
_container_namespace_expr: &Expr,
_member: &Member,
_ty: &Type,
access: Expr,
) -> Result<TokenStream> {
let child_name = &self.name;
let child_namespace = &self.namespace;
Ok(quote! {
if #access {
builder.append(::xso::exports::minidom::Node::Element(::xso::exports::minidom::Element::builder(#child_name, #child_namespace).build()))
} else {
builder
}
})
}
fn build_set_namespace(
&self,
_input: &Ident,
_ty: &Type,
_access: Expr,
) -> Result<TokenStream> {
Ok(TokenStream::default())
}
}