1use proc_macro2::{Span, TokenStream};
12use quote::quote;
13use syn::*;
14
15use crate::error_message::{FieldName, ParentRef};
16use crate::meta::{NameRef, NamespaceRef};
17use crate::scope::{AsItemsScope, FromEventsScope};
18use crate::types::{bool_ty, empty_builder_ty, u8_ty};
19
20use super::{Field, FieldBuilderPart, FieldIteratorPart, FieldTempInit, NestedMatcher};
21
22pub(super) struct FlagField {
24 pub(super) xml_namespace: NamespaceRef,
26
27 pub(super) xml_name: NameRef,
29}
30
31impl Field for FlagField {
32 fn make_builder_part(
33 &self,
34 scope: &FromEventsScope,
35 container_name: &ParentRef,
36 member: &Member,
37 _ty: &Type,
38 ) -> Result<FieldBuilderPart> {
39 let field_access = scope.access_field(member);
40
41 let unknown_attr_err = format!(
42 "Unknown attribute in flag child {} in {}.",
43 FieldName(&member),
44 container_name
45 );
46 let unknown_child_err = format!(
47 "Unknown child in flag child {} in {}.",
48 FieldName(&member),
49 container_name
50 );
51 let unknown_text_err = format!(
52 "Unexpected text in flag child {} in {}.",
53 FieldName(&member),
54 container_name
55 );
56
57 let xml_namespace = &self.xml_namespace;
58 let xml_name = &self.xml_name;
59
60 Ok(FieldBuilderPart::Nested {
61 extra_defs: TokenStream::new(),
62 value: FieldTempInit {
63 ty: bool_ty(Span::call_site()),
64 init: quote! { false },
65 },
66 matcher: NestedMatcher::Selective(quote! {
67 if name.0 == #xml_namespace && name.1 == #xml_name {
68 ::xso::fromxml::Empty {
69 attributeerr: #unknown_attr_err,
70 childerr: #unknown_child_err,
71 texterr: #unknown_text_err,
72 }.start(attrs).map_err(
73 ::xso::error::FromEventsError::Invalid
74 )
75 } else {
76 ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch {
77 name,
78 attrs,
79 })
80 }
81 }),
82 builder: empty_builder_ty(Span::call_site()),
83 collect: quote! {
84 #field_access = true;
85 },
86 finalize: quote! {
87 #field_access
88 },
89 })
90 }
91
92 fn make_iterator_part(
93 &self,
94 _scope: &AsItemsScope,
95 _container_name: &ParentRef,
96 bound_name: &Ident,
97 _member: &Member,
98 _ty: &Type,
99 ) -> Result<FieldIteratorPart> {
100 let xml_namespace = &self.xml_namespace;
101 let xml_name = &self.xml_name;
102
103 Ok(FieldIteratorPart::Content {
104 extra_defs: TokenStream::new(),
105 value: FieldTempInit {
106 init: quote! {
107 if *#bound_name {
108 3
109 } else {
110 1
111 }
112 },
113 ty: u8_ty(Span::call_site()),
114 },
115 generator: quote! {
116 {
117 #bound_name = #bound_name.wrapping_sub(1);
120 match #bound_name {
121 0 => ::core::result::Result::<_, ::xso::error::Error>::Ok(::core::option::Option::None),
122 1 => ::core::result::Result::Ok(::core::option::Option::Some(
123 ::xso::Item::ElementFoot
124 )),
125 2 => ::core::result::Result::Ok(::core::option::Option::Some(
126 ::xso::Item::ElementHeadStart(
127 ::xso::exports::rxml::Namespace::from(#xml_namespace),
128 ::xso::exports::alloc::borrow::Cow::Borrowed(#xml_name),
129 )
130 )),
131 _ => unreachable!(),
132 }
133 }
134 },
135 })
136 }
137}