xso_proc/field/
attribute.rsuse quote::{quote, ToTokens};
use syn::*;
use crate::error_message::{self, ParentRef};
use crate::meta::{Flag, NameRef, NamespaceRef};
use crate::scope::{AsItemsScope, FromEventsScope};
use crate::types::{
as_optional_xml_text_fn, default_fn, from_xml_text_fn, text_codec_decode_fn,
text_codec_encode_fn,
};
use super::{Field, FieldBuilderPart, FieldIteratorPart, FieldTempInit};
pub(super) struct AttributeField {
pub(super) xml_namespace: Option<NamespaceRef>,
pub(super) xml_name: NameRef,
pub(super) default_: Flag,
pub(super) codec: Option<Expr>,
}
impl Field for AttributeField {
fn make_builder_part(
&self,
scope: &FromEventsScope,
container_name: &ParentRef,
member: &Member,
ty: &Type,
) -> Result<FieldBuilderPart> {
let FromEventsScope { ref attrs, .. } = scope;
let ty = ty.clone();
let xml_namespace = &self.xml_namespace;
let xml_name = &self.xml_name;
let missing_msg = error_message::on_missing_attribute(container_name, member);
let xml_namespace = match xml_namespace {
Some(v) => v.to_token_stream(),
None => quote! {
::xso::exports::rxml::Namespace::none()
},
};
let finalize = match self.codec {
Some(ref codec) => {
let decode = text_codec_decode_fn(ty.clone());
quote! {
|value| #decode(&#codec, value)
}
}
None => {
let from_xml_text = from_xml_text_fn(ty.clone());
quote! { #from_xml_text }
}
};
let on_absent = match self.default_ {
Flag::Absent => quote! {
return ::core::result::Result::Err(::xso::error::Error::Other(#missing_msg).into())
},
Flag::Present(_) => {
let default_ = default_fn(ty.clone());
quote! {
#default_()
}
}
};
Ok(FieldBuilderPart::Init {
value: FieldTempInit {
init: quote! {
match #attrs.remove(#xml_namespace, #xml_name).map(#finalize).transpose()? {
::core::option::Option::Some(v) => v,
::core::option::Option::None => #on_absent,
}
},
ty: ty.clone(),
},
})
}
fn make_iterator_part(
&self,
_scope: &AsItemsScope,
_container_name: &ParentRef,
bound_name: &Ident,
_member: &Member,
ty: &Type,
) -> Result<FieldIteratorPart> {
let xml_namespace = match self.xml_namespace {
Some(ref v) => quote! { ::xso::exports::rxml::Namespace::from(#v) },
None => quote! {
::xso::exports::rxml::Namespace::NONE
},
};
let xml_name = &self.xml_name;
let generator = match self.codec {
Some(ref codec) => {
let encode = text_codec_encode_fn(ty.clone());
quote! { #encode(&#codec, #bound_name)? }
}
None => {
let as_optional_xml_text = as_optional_xml_text_fn(ty.clone());
quote! { #as_optional_xml_text(#bound_name)? }
}
};
Ok(FieldIteratorPart::Header {
generator: quote! {
#generator.map(|#bound_name| ::xso::Item::Attribute(
#xml_namespace,
::std::borrow::Cow::Borrowed(#xml_name),
#bound_name,
));
},
})
}
}