use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::*;
use crate::common::Scope;
use crate::error_message::ParentRef;
use crate::types::*;
use super::{Field, FieldFromEventsPart, FieldIntoEventsPart, FieldTempInit};
#[derive(Debug)]
pub(crate) struct TextField {
pub(super) codec: Option<Type>,
}
impl TextField {
pub(super) fn new(_attr_span: &Span, codec: Option<Type>) -> Result<Self> {
Ok(Self { codec })
}
}
impl Field for TextField {
fn is_text(&self) -> bool {
true
}
fn build_from_events_builder(
&self,
scope: &Scope,
_container_name: &ParentRef,
_tempname: Ident,
member: &Member,
ty: &Type,
) -> Result<FieldFromEventsPart> {
let Scope { ref text, .. } = scope;
let access = scope.access_field(member);
let decode = match self.codec {
Some(ref codec_ty) => {
let codec_ty_decode = text_codec_decode_fn(codec_ty.clone(), ty.clone());
quote! {
#codec_ty_decode(#access.0.as_str())?
}
}
None => {
let ty_from_xml_text = from_xml_text_fn(ty.clone());
quote! {
#ty_from_xml_text(#access.0.as_str())?
}
}
};
let field_ty = Type::Tuple(TypeTuple {
paren_token: syn::token::Paren::default(),
elems: [string_ty(Span::call_site()), phantom_ty(ty.clone())]
.into_iter()
.collect(),
});
Ok(FieldFromEventsPart::Text {
temp: FieldTempInit {
ty: field_ty,
init: quote! { (
::std::string::String::new(),
::std::marker::PhantomData::<#ty>,
) },
},
accum: quote! {
#access.0.push_str(&#text);
},
finalize: decode,
})
}
fn build_into_events_iterator(
&self,
_scope: &Scope,
_container_name: &ParentRef,
tempname: Ident,
_member: &Member,
ty: &Type,
) -> Result<FieldIntoEventsPart> {
let encode = match self.codec {
Some(ref codec_ty) => {
let codec_ty_encode = text_codec_encode_fn(codec_ty.clone(), ty.clone());
quote! {
#codec_ty_encode(#tempname).unwrap_or_else(String::new)
}
}
None => {
let ty_into_xml_text = into_xml_text_fn(ty.clone());
quote! {
#ty_into_xml_text(#tempname)
}
}
};
Ok(FieldIntoEventsPart::ContentConsume {
prepare: quote! { #tempname },
emitter: quote! {
{
let value = #encode;
if value.len() > 0 {
::std::option::Option::Some(::xso::exports::rxml::Event::Text(::xso::exports::rxml::parser::EventMetrics::zero(), value.try_into()?))
} else {
::std::option::Option::None
}
}
},
})
}
fn build_set_namespace(
&self,
_input: &Ident,
_ty: &Type,
_access: Expr,
) -> Result<TokenStream> {
Ok(TokenStream::default())
}
}