1use proc_macro2::Span;
12use quote::{quote, quote_spanned};
13use syn::{spanned::Spanned, *};
14
15use crate::common::GenericsInfo;
16use crate::error_message::ParentRef;
17use crate::scope::{AsItemsScope, FromEventsScope};
18use crate::types::{
19 as_xml_text_fn, as_xml_text_trait, from_xml_text_fn, from_xml_text_trait, phantom_fn_ret_ty,
20 string_ty, text_codec_decode_fn, text_codec_encode_fn,
21};
22
23use super::{Field, FieldBuilderPart, FieldIteratorPart, FieldTempInit};
24
25pub(super) struct TextField {
27 pub(super) codec: Option<Expr>,
29}
30
31impl Field for TextField {
32 fn make_builder_part(
33 &self,
34 scope: &FromEventsScope,
35 generics: &mut GenericsInfo,
36 _container_name: &ParentRef,
37 member: &Member,
38 ty: &Type,
39 ) -> Result<FieldBuilderPart> {
40 let FromEventsScope { ref text, .. } = scope;
41 let field_access = scope.access_field(member);
42 let finalize = match self.codec {
43 Some(ref codec) => {
44 let span = codec.span();
45 let decode = text_codec_decode_fn(ty.clone(), span);
46 quote_spanned! { span=>
47 #decode(&#codec, #field_access.0)?
48 }
49 }
50 None => {
51 generics.add_bound_if_generic(ty, from_xml_text_trait(Span::call_site()));
52 let from_xml_text = from_xml_text_fn(ty.clone());
53 quote! { #from_xml_text(#field_access.0)? }
54 }
55 };
56
57 let ty = Type::Tuple(TypeTuple {
64 paren_token: token::Paren::default(),
65 elems: [string_ty(Span::call_site()), phantom_fn_ret_ty(ty.clone())]
66 .into_iter()
67 .collect(),
68 });
69
70 Ok(FieldBuilderPart::Text {
71 value: FieldTempInit {
72 init: quote! { (::xso::exports::alloc::string::String::new(), core::marker::PhantomData) },
73 ty,
74 },
75 collect: quote! {
76 #field_access.0.push_str(#text.as_str());
77 },
78 finalize,
79 })
80 }
81
82 fn make_iterator_part(
83 &self,
84 _scope: &AsItemsScope,
85 generics: &mut GenericsInfo,
86 _container_name: &ParentRef,
87 bound_name: &Ident,
88 _member: &Member,
89 ty: &Type,
90 ) -> Result<FieldIteratorPart> {
91 let generator = match self.codec {
92 Some(ref codec) => {
93 let span = codec.span();
94 let encode = text_codec_encode_fn(ty.clone(), span);
95 let mut bound_name = bound_name.clone();
100 bound_name.set_span(span);
101 quote_spanned! { span=> #encode(&#codec, #bound_name)? }
102 }
103 None => {
104 generics.add_bound_if_generic(ty, as_xml_text_trait(Span::call_site()));
105 let as_xml_text = as_xml_text_fn(ty.clone());
106 quote! { ::core::option::Option::Some(#as_xml_text(#bound_name)?) }
107 }
108 };
109
110 Ok(FieldIteratorPart::Text { generator })
111 }
112
113 fn captures_text(&self) -> bool {
114 true
115 }
116}