1use proc_macro2::Span;
12use quote::{quote, quote_spanned};
13use syn::{spanned::Spanned, *};
14
15use crate::error_message::ParentRef;
16use crate::scope::{AsItemsScope, FromEventsScope};
17use crate::types::{
18 as_xml_text_fn, from_xml_text_fn, string_ty, text_codec_decode_fn, text_codec_encode_fn,
19};
20
21use super::{Field, FieldBuilderPart, FieldIteratorPart, FieldTempInit};
22
23pub(super) struct TextField {
25 pub(super) codec: Option<Expr>,
27}
28
29impl Field for TextField {
30 fn make_builder_part(
31 &self,
32 scope: &FromEventsScope,
33 _container_name: &ParentRef,
34 member: &Member,
35 ty: &Type,
36 ) -> Result<FieldBuilderPart> {
37 let FromEventsScope { ref text, .. } = scope;
38 let field_access = scope.access_field(member);
39 let finalize = match self.codec {
40 Some(ref codec) => {
41 let span = codec.span();
42 let decode = text_codec_decode_fn(ty.clone(), span);
43 quote_spanned! { span=>
44 #decode(&#codec, #field_access)?
45 }
46 }
47 None => {
48 let from_xml_text = from_xml_text_fn(ty.clone());
49 quote! { #from_xml_text(#field_access)? }
50 }
51 };
52
53 Ok(FieldBuilderPart::Text {
54 value: FieldTempInit {
55 init: quote! { ::xso::exports::alloc::string::String::new() },
56 ty: string_ty(Span::call_site()),
57 },
58 collect: quote! {
59 #field_access.push_str(#text.as_str());
60 },
61 finalize,
62 })
63 }
64
65 fn make_iterator_part(
66 &self,
67 _scope: &AsItemsScope,
68 _container_name: &ParentRef,
69 bound_name: &Ident,
70 _member: &Member,
71 ty: &Type,
72 ) -> Result<FieldIteratorPart> {
73 let generator = match self.codec {
74 Some(ref codec) => {
75 let span = codec.span();
76 let encode = text_codec_encode_fn(ty.clone(), span);
77 let mut bound_name = bound_name.clone();
82 bound_name.set_span(span);
83 quote_spanned! { span=> #encode(&#codec, #bound_name)? }
84 }
85 None => {
86 let as_xml_text = as_xml_text_fn(ty.clone());
87 quote! { ::core::option::Option::Some(#as_xml_text(#bound_name)?) }
88 }
89 };
90
91 Ok(FieldIteratorPart::Text { generator })
92 }
93
94 fn captures_text(&self) -> bool {
95 true
96 }
97}