1use std::collections::HashMap;
10
11use proc_macro2::{Span, TokenStream};
12use quote::{quote, ToTokens};
13use syn::*;
14
15use crate::common::{AsXmlParts, FromXmlParts, GenericsInfo, ItemDef, XmlNameMatcher};
16use crate::compound::Compound;
17use crate::error_message::ParentRef;
18use crate::meta::{reject_key, Flag, NameRef, NamespaceRef, QNameRef, XmlCompoundMeta};
19use crate::state::{AsItemsStateMachine, FromEventsMatchMode, FromEventsStateMachine};
20use crate::structs::StructInner;
21use crate::types::ref_ty;
22
23struct NameVariant {
26 name: NameRef,
28
29 ident: Ident,
31
32 inner: Compound,
34}
35
36impl NameVariant {
37 fn new(decl: &Variant, enum_namespace: &NamespaceRef) -> Result<Self> {
39 let XmlCompoundMeta {
43 span: meta_span,
44 qname: QNameRef { namespace, name },
45 exhaustive,
46 debug,
47 builder,
48 iterator,
49 on_unknown_attribute,
50 on_unknown_child,
51 transparent,
52 discard,
53 deserialize_callback,
54 attribute,
55 value,
56 } = XmlCompoundMeta::parse_from_attributes(&decl.attrs)?;
57
58 reject_key!(debug flag not on "enum variants" only on "enums and structs");
59 reject_key!(exhaustive flag not on "enum variants" only on "enums");
60 reject_key!(namespace not on "enum variants" only on "enums and structs");
61 reject_key!(builder not on "enum variants" only on "enums and structs");
62 reject_key!(iterator not on "enum variants" only on "enums and structs");
63 reject_key!(transparent flag not on "named enum variants" only on "structs");
64 reject_key!(deserialize_callback not on "enum variants" only on "enums and structs");
65 reject_key!(attribute not on "enum variants" only on "attribute-switched enums");
66 reject_key!(value not on "name-switched enum variants" only on "attribute-switched enum variants");
67
68 let Some(name) = name else {
69 return Err(Error::new(
70 meta_span,
71 "`name` is required on name-switched enum variants",
72 ));
73 };
74
75 Ok(Self {
76 name,
77 ident: decl.ident.clone(),
78 inner: Compound::from_fields(
79 &decl.fields,
80 enum_namespace,
81 on_unknown_attribute,
82 on_unknown_child,
83 discard,
84 )?,
85 })
86 }
87
88 fn make_from_events_statemachine(
89 &self,
90 generics: &mut GenericsInfo,
91 enum_ident: &Ident,
92 state_ty_ident: &Ident,
93 ) -> Result<FromEventsStateMachine> {
94 let xml_name = &self.name;
95
96 let mut inner_generics = generics.scoped_for(&self.inner.to_tuple_ty().into())?;
97
98 let result = self
99 .inner
100 .make_from_events_statemachine(
101 &mut inner_generics,
102 state_ty_ident,
103 &ParentRef::Named(Path {
104 leading_colon: None,
105 segments: [
106 PathSegment::from(enum_ident.clone()),
107 self.ident.clone().into(),
108 ]
109 .into_iter()
110 .collect(),
111 }),
112 &self.ident.to_string(),
113 )?
114 .with_augmented_init(|init| {
115 quote! {
116 if name.1 != #xml_name {
117 ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch {
118 name,
119 attrs,
120 })
121 } else {
122 #init
123 }
124 }
125 })
126 .compile();
127
128 generics.extend_bounds(inner_generics.into_new_bounds());
129
130 Ok(result)
131 }
132
133 fn make_as_item_iter_statemachine(
134 &self,
135 generics: &mut GenericsInfo,
136 xml_namespace: &NamespaceRef,
137 enum_ident: &Ident,
138 state_ty_ident: &Ident,
139 item_iter_ty_lifetime: &Lifetime,
140 ) -> Result<AsItemsStateMachine> {
141 let xml_name = &self.name;
142
143 Ok(self
144 .inner
145 .make_as_item_iter_statemachine(
146 generics,
147 &ParentRef::Named(Path {
148 leading_colon: None,
149 segments: [
150 PathSegment::from(enum_ident.clone()),
151 self.ident.clone().into(),
152 ]
153 .into_iter()
154 .collect(),
155 }),
156 state_ty_ident,
157 &self.ident.to_string(),
158 item_iter_ty_lifetime,
159 )?
160 .with_augmented_init(|init| {
161 quote! {
162 let name = (
163 ::xso::exports::rxml::Namespace::from(#xml_namespace),
164 ::xso::exports::alloc::borrow::Cow::Borrowed(#xml_name),
165 );
166 #init
167 }
168 })
169 .compile())
170 }
171}
172
173struct NameSwitchedEnum {
176 namespace: NamespaceRef,
178
179 variants: Vec<NameVariant>,
181
182 exhaustive: bool,
184}
185
186impl NameSwitchedEnum {
187 fn new<'x, I: IntoIterator<Item = &'x Variant>>(
188 namespace: NamespaceRef,
189 exhaustive: Flag,
190 variant_iter: I,
191 ) -> Result<Self> {
192 let mut variants = Vec::new();
193 let mut seen_names = HashMap::new();
194 for variant in variant_iter {
195 let variant = NameVariant::new(variant, &namespace)?;
196 if let Some(other) = seen_names.get(&variant.name) {
197 return Err(Error::new_spanned(
198 variant.name,
199 format!(
200 "duplicate `name` in enum: variants {} and {} have the same XML name",
201 other, variant.ident
202 ),
203 ));
204 }
205 seen_names.insert(variant.name.clone(), variant.ident.clone());
206 variants.push(variant);
207 }
208
209 Ok(Self {
210 namespace,
211 variants,
212 exhaustive: exhaustive.is_set(),
213 })
214 }
215
216 fn xml_name_matcher(&self) -> Result<XmlNameMatcher> {
221 Ok(XmlNameMatcher::InNamespace(
222 self.namespace.to_token_stream(),
223 ))
224 }
225
226 fn make_from_events_statemachine(
228 &self,
229 generics: &mut GenericsInfo,
230 target_ty_ident: &Ident,
231 state_ty_ident: &Ident,
232 ) -> Result<FromEventsStateMachine> {
233 let xml_namespace = &self.namespace;
234
235 let mut statemachine = FromEventsStateMachine::new();
236 for variant in self.variants.iter() {
237 statemachine.merge(variant.make_from_events_statemachine(
238 generics,
239 target_ty_ident,
240 state_ty_ident,
241 )?);
242 }
243
244 statemachine.set_pre_init(quote! {
245 if name.0 != #xml_namespace {
246 return ::core::result::Result::Err(::xso::error::FromEventsError::Mismatch {
247 name,
248 attrs,
249 })
250 }
251 });
252
253 if self.exhaustive {
254 let mismatch_err = format!("This is not a {} element.", target_ty_ident);
255 statemachine.set_fallback(quote! {
256 ::core::result::Result::Err(::xso::error::FromEventsError::Invalid(
257 ::xso::error::Error::Other(#mismatch_err),
258 ))
259 })
260 }
261
262 Ok(statemachine)
263 }
264
265 fn make_as_item_iter_statemachine(
267 &self,
268 generics: &mut GenericsInfo,
269 target_ty_ident: &Ident,
270 state_ty_ident: &Ident,
271 item_iter_ty_lifetime: &Lifetime,
272 ) -> Result<AsItemsStateMachine> {
273 let mut statemachine = AsItemsStateMachine::new();
274 for variant in self.variants.iter() {
275 statemachine.merge(variant.make_as_item_iter_statemachine(
276 generics,
277 &self.namespace,
278 target_ty_ident,
279 state_ty_ident,
280 item_iter_ty_lifetime,
281 )?);
282 }
283
284 Ok(statemachine)
285 }
286}
287
288struct ValueVariant {
291 value: String,
293
294 ident: Ident,
296
297 inner: Compound,
299}
300
301impl ValueVariant {
302 fn new(decl: &Variant, enum_namespace: &NamespaceRef) -> Result<Self> {
304 let XmlCompoundMeta {
308 span: meta_span,
309 qname: QNameRef { namespace, name },
310 exhaustive,
311 debug,
312 builder,
313 iterator,
314 on_unknown_attribute,
315 on_unknown_child,
316 transparent,
317 discard,
318 deserialize_callback,
319 attribute,
320 value,
321 } = XmlCompoundMeta::parse_from_attributes(&decl.attrs)?;
322
323 reject_key!(debug flag not on "enum variants" only on "enums and structs");
324 reject_key!(exhaustive flag not on "enum variants" only on "enums");
325 reject_key!(namespace not on "enum variants" only on "enums and structs");
326 reject_key!(name not on "attribute-switched enum variants" only on "enums, structs and name-switched enum variants");
327 reject_key!(builder not on "enum variants" only on "enums and structs");
328 reject_key!(iterator not on "enum variants" only on "enums and structs");
329 reject_key!(transparent flag not on "named enum variants" only on "structs");
330 reject_key!(deserialize_callback not on "enum variants" only on "enums and structs");
331 reject_key!(attribute not on "enum variants" only on "attribute-switched enums");
332
333 let Some(value) = value else {
334 return Err(Error::new(
335 meta_span,
336 "`value` is required on attribute-switched enum variants",
337 ));
338 };
339
340 Ok(Self {
341 value: value.value(),
342 ident: decl.ident.clone(),
343 inner: Compound::from_fields(
344 &decl.fields,
345 enum_namespace,
346 on_unknown_attribute,
347 on_unknown_child,
348 discard,
349 )?,
350 })
351 }
352
353 fn make_from_events_statemachine(
354 &self,
355 generics: &mut GenericsInfo,
356 enum_ident: &Ident,
357 state_ty_ident: &Ident,
358 ) -> Result<FromEventsStateMachine> {
359 let value = &self.value;
360
361 let mut inner_generics = generics.scoped_for(&self.inner.to_tuple_ty().into())?;
362
363 let result = self
364 .inner
365 .make_from_events_statemachine(
366 &mut inner_generics,
367 state_ty_ident,
368 &ParentRef::Named(Path {
369 leading_colon: None,
370 segments: [
371 PathSegment::from(enum_ident.clone()),
372 self.ident.clone().into(),
373 ]
374 .into_iter()
375 .collect(),
376 }),
377 &self.ident.to_string(),
378 )?
379 .with_augmented_init(|init| {
380 quote! {
381 #value => { #init },
382 }
383 })
384 .compile();
385
386 generics.extend_bounds(inner_generics.into_new_bounds());
387
388 Ok(result)
389 }
390
391 fn make_as_item_iter_statemachine(
392 &self,
393 generics: &mut GenericsInfo,
394 elem_namespace: &NamespaceRef,
395 elem_name: &NameRef,
396 attr_namespace: &TokenStream,
397 attr_name: &NameRef,
398 enum_ident: &Ident,
399 state_ty_ident: &Ident,
400 item_iter_ty_lifetime: &Lifetime,
401 ) -> Result<AsItemsStateMachine> {
402 let attr_value = &self.value;
403
404 Ok(self
405 .inner
406 .make_as_item_iter_statemachine(
407 generics,
408 &ParentRef::Named(Path {
409 leading_colon: None,
410 segments: [
411 PathSegment::from(enum_ident.clone()),
412 self.ident.clone().into(),
413 ]
414 .into_iter()
415 .collect(),
416 }),
417 state_ty_ident,
418 &self.ident.to_string(),
419 item_iter_ty_lifetime,
420 )?
421 .with_augmented_init(|init| {
422 quote! {
423 let name = (
424 ::xso::exports::rxml::Namespace::from(#elem_namespace),
425 ::xso::exports::alloc::borrow::Cow::Borrowed(#elem_name),
426 );
427 #init
428 }
429 })
430 .with_extra_header_state(
431 quote::format_ident!("{}Discriminator", &self.ident.to_string()),
434 quote! {
435 ::xso::Item::Attribute(
436 #attr_namespace,
437 ::xso::exports::alloc::borrow::Cow::Borrowed(#attr_name),
438 ::xso::exports::alloc::borrow::Cow::Borrowed(#attr_value),
439 )
440 },
441 )
442 .compile())
443 }
444}
445
446struct AttributeSwitchedEnum {
449 elem_namespace: NamespaceRef,
451
452 elem_name: NameRef,
454
455 attr_namespace: Option<NamespaceRef>,
458
459 attr_name: NameRef,
461
462 variants: Vec<ValueVariant>,
464}
465
466impl AttributeSwitchedEnum {
467 fn new<'x, I: IntoIterator<Item = &'x Variant>>(
468 elem_namespace: NamespaceRef,
469 elem_name: NameRef,
470 attr_namespace: Option<NamespaceRef>,
471 attr_name: NameRef,
472 variant_iter: I,
473 ) -> Result<Self> {
474 let mut variants = Vec::new();
475 let mut seen_values = HashMap::new();
476 for variant in variant_iter {
477 let variant = ValueVariant::new(variant, &elem_namespace)?;
478 if let Some(other) = seen_values.get(&variant.value) {
479 return Err(Error::new_spanned(
480 variant.value,
481 format!(
482 "duplicate `value` in enum: variants {} and {} have the same attribute value",
483 other, variant.ident
484 ),
485 ));
486 }
487 seen_values.insert(variant.value.clone(), variant.ident.clone());
488 variants.push(variant);
489 }
490
491 Ok(Self {
492 elem_namespace,
493 elem_name,
494 attr_namespace,
495 attr_name,
496 variants,
497 })
498 }
499
500 fn xml_name_matcher(&self) -> Result<XmlNameMatcher> {
505 Ok(XmlNameMatcher::Specific(
506 self.elem_namespace.to_token_stream(),
507 self.elem_name.to_token_stream(),
508 ))
509 }
510
511 fn make_from_events_statemachine(
513 &self,
514 generics: &mut GenericsInfo,
515 target_ty_ident: &Ident,
516 state_ty_ident: &Ident,
517 ) -> Result<FromEventsStateMachine> {
518 let elem_namespace = &self.elem_namespace;
519 let elem_name = &self.elem_name;
520 let attr_namespace = match self.attr_namespace.as_ref() {
521 Some(v) => v.to_token_stream(),
522 None => quote! {
523 ::xso::exports::rxml::Namespace::none()
524 },
525 };
526 let attr_name = &self.attr_name;
527
528 let mut statemachine = FromEventsStateMachine::new();
529 for variant in self.variants.iter() {
530 statemachine.merge(variant.make_from_events_statemachine(
531 generics,
532 target_ty_ident,
533 state_ty_ident,
534 )?);
535 }
536
537 statemachine.set_pre_init(quote! {
538 let attr = {
539 if name.0 != #elem_namespace || name.1 != #elem_name {
540 return ::core::result::Result::Err(
541 ::xso::error::FromEventsError::Mismatch {
542 name,
543 attrs,
544 },
545 );
546 }
547
548 let ::core::option::Option::Some(attr) = attrs.remove(#attr_namespace, #attr_name) else {
549 return ::core::result::Result::Err(
550 ::xso::error::FromEventsError::Invalid(
551 ::xso::error::Error::Other("Missing discriminator attribute.")
552 ),
553 );
554 };
555
556 attr
557 };
558 });
559 statemachine.set_fallback(quote! {
560 ::core::result::Result::Err(
561 ::xso::error::FromEventsError::Invalid(
562 ::xso::error::Error::Other("Unknown value for discriminator attribute.")
563 ),
564 )
565 });
566 statemachine.set_match_mode(FromEventsMatchMode::Matched {
567 expr: quote! { attr.as_str() },
568 });
569
570 Ok(statemachine)
571 }
572
573 fn make_as_item_iter_statemachine(
575 &self,
576 generics: &mut GenericsInfo,
577 target_ty_ident: &Ident,
578 state_ty_ident: &Ident,
579 item_iter_ty_lifetime: &Lifetime,
580 ) -> Result<AsItemsStateMachine> {
581 let attr_namespace = match self.attr_namespace.as_ref() {
582 Some(v) => v.to_token_stream(),
583 None => quote! {
584 ::xso::exports::rxml::Namespace::NONE
585 },
586 };
587
588 let mut statemachine = AsItemsStateMachine::new();
589 for variant in self.variants.iter() {
590 statemachine.merge(variant.make_as_item_iter_statemachine(
591 generics,
592 &self.elem_namespace,
593 &self.elem_name,
594 &attr_namespace,
595 &self.attr_name,
596 target_ty_ident,
597 state_ty_ident,
598 item_iter_ty_lifetime,
599 )?);
600 }
601
602 Ok(statemachine)
603 }
604}
605
606struct DynamicVariant {
608 ident: Ident,
610
611 inner: StructInner,
613}
614
615impl DynamicVariant {
616 fn new(variant: &Variant) -> Result<Self> {
617 let ident = variant.ident.clone();
618 let meta = XmlCompoundMeta::parse_from_attributes(&variant.attrs)?;
619
620 let XmlCompoundMeta {
624 span: _,
625 qname: _, ref exhaustive,
627 ref debug,
628 ref builder,
629 ref iterator,
630 on_unknown_attribute: _, on_unknown_child: _, transparent: _, discard: _, ref deserialize_callback,
635 ref attribute,
636 ref value,
637 } = meta;
638
639 reject_key!(debug flag not on "enum variants" only on "enums and structs");
640 reject_key!(exhaustive flag not on "enum variants" only on "enums");
641 reject_key!(builder not on "enum variants" only on "enums and structs");
642 reject_key!(iterator not on "enum variants" only on "enums and structs");
643 reject_key!(deserialize_callback not on "enum variants" only on "enums and structs");
644 reject_key!(attribute not on "enum variants" only on "attribute-switched enums");
645 reject_key!(value not on "dynamic enum variants" only on "attribute-switched enum variants");
646
647 let inner = StructInner::new(meta, &variant.fields)?;
648 Ok(Self { ident, inner })
649 }
650}
651
652struct DynamicEnum {
655 variants: Vec<DynamicVariant>,
657}
658
659impl DynamicEnum {
660 fn new<'x, I: IntoIterator<Item = &'x Variant>>(variant_iter: I) -> Result<Self> {
661 let mut variants = Vec::new();
662 for variant in variant_iter {
663 variants.push(DynamicVariant::new(variant)?);
664 }
665
666 Ok(Self { variants })
667 }
668
669 fn xml_name_matcher(&self) -> Result<XmlNameMatcher> {
674 let mut iter = self.variants.iter();
675 let Some(first) = iter.next() else {
676 return Ok(XmlNameMatcher::Custom(quote! {
680 ::xso::fromxml::XmlNameMatcher::<'static>::Specific("", "")
681 }));
682 };
683
684 let first_matcher = first.inner.xml_name_matcher()?;
685 let mut composition = quote! { #first_matcher };
686 for variant in iter {
687 let next_matcher = variant.inner.xml_name_matcher()?;
688 composition.extend(quote! { .superset(#next_matcher) });
689 }
690
691 Ok(XmlNameMatcher::Custom(composition))
692 }
693
694 fn make_from_events_statemachine(
696 &self,
697 generics: &mut GenericsInfo,
698 target_ty_ident: &Ident,
699 state_ty_ident: &Ident,
700 ) -> Result<FromEventsStateMachine> {
701 let mut statemachine = FromEventsStateMachine::new();
702 for variant in self.variants.iter() {
703 let mut inner_generics = match variant.inner {
704 StructInner::Transparent { ref ty, .. } => generics.scoped_for(ty)?,
705 StructInner::Compound { ref inner, .. } => {
706 generics.scoped_for(&inner.to_tuple_ty().into())?
707 }
708 };
709 let submachine = variant.inner.make_from_events_statemachine(
710 &mut inner_generics,
711 state_ty_ident,
712 &ParentRef::Named(Path {
713 leading_colon: None,
714 segments: [
715 PathSegment::from(target_ty_ident.clone()),
716 variant.ident.clone().into(),
717 ]
718 .into_iter()
719 .collect(),
720 }),
721 &variant.ident.to_string(),
722 )?;
723
724 generics.extend_bounds(inner_generics.into_new_bounds());
725
726 statemachine.merge(submachine.compile());
727 }
728
729 Ok(statemachine)
730 }
731
732 fn make_as_item_iter_statemachine(
734 &self,
735 generics: &mut GenericsInfo,
736 target_ty_ident: &Ident,
737 state_ty_ident: &Ident,
738 item_iter_ty_lifetime: &Lifetime,
739 ) -> Result<AsItemsStateMachine> {
740 let mut statemachine = AsItemsStateMachine::new();
741 for variant in self.variants.iter() {
742 let submachine = variant.inner.make_as_item_iter_statemachine(
743 generics,
744 &ParentRef::Named(Path {
745 leading_colon: None,
746 segments: [
747 PathSegment::from(target_ty_ident.clone()),
748 variant.ident.clone().into(),
749 ]
750 .into_iter()
751 .collect(),
752 }),
753 state_ty_ident,
754 &variant.ident.to_string(),
755 item_iter_ty_lifetime,
756 )?;
757
758 statemachine.merge(submachine.compile());
759 }
760
761 Ok(statemachine)
762 }
763}
764
765enum EnumInner {
767 NameSwitched(NameSwitchedEnum),
770
771 AttributeSwitched(AttributeSwitchedEnum),
774
775 Dynamic(DynamicEnum),
777}
778
779impl EnumInner {
780 fn new<'x, I: IntoIterator<Item = &'x Variant>>(
781 meta: XmlCompoundMeta,
782 variant_iter: I,
783 ) -> Result<Self> {
784 let XmlCompoundMeta {
788 span,
789 qname: QNameRef { namespace, name },
790 exhaustive,
791 debug,
792 builder,
793 iterator,
794 on_unknown_attribute,
795 on_unknown_child,
796 transparent,
797 discard,
798 deserialize_callback,
799 attribute,
800 value,
801 } = meta;
802
803 assert!(builder.is_none());
807 assert!(iterator.is_none());
808 assert!(!debug.is_set());
809 assert!(deserialize_callback.is_none());
810
811 reject_key!(transparent flag not on "enums" only on "structs");
812 reject_key!(on_unknown_attribute not on "enums" only on "enum variants and structs");
813 reject_key!(on_unknown_child not on "enums" only on "enum variants and structs");
814 reject_key!(discard vec not on "enums" only on "enum variants and structs");
815 reject_key!(value not on "enums" only on "attribute-switched enum variants");
816
817 if let Some(attribute) = attribute {
818 let Some(attr_name) = attribute.qname.name else {
819 return Err(Error::new(
820 attribute.span,
821 "missing `name` for `attribute` key",
822 ));
823 };
824
825 let attr_namespace = attribute.qname.namespace;
826
827 let Some(elem_namespace) = namespace else {
828 let mut error =
829 Error::new(span, "missing `namespace` key on attribute-switched enum");
830 error.combine(Error::new(
831 attribute.span,
832 "enum is attribute-switched because of the `attribute` key here",
833 ));
834 return Err(error);
835 };
836
837 let Some(elem_name) = name else {
838 let mut error = Error::new(span, "missing `name` key on attribute-switched enum");
839 error.combine(Error::new(
840 attribute.span,
841 "enum is attribute-switched because of the `attribute` key here",
842 ));
843 return Err(error);
844 };
845
846 if !exhaustive.is_set() {
847 return Err(Error::new(
848 span,
849 "attribute-switched enums must be marked as `exhaustive`. non-exhaustive attribute-switched enums are not supported."
850 ));
851 }
852
853 Ok(Self::AttributeSwitched(AttributeSwitchedEnum::new(
854 elem_namespace,
855 elem_name,
856 attr_namespace,
857 attr_name,
858 variant_iter,
859 )?))
860 } else if let Some(namespace) = namespace {
861 reject_key!(name not on "name-switched enums" only on "their variants");
862 Ok(Self::NameSwitched(NameSwitchedEnum::new(
863 namespace,
864 exhaustive,
865 variant_iter,
866 )?))
867 } else {
868 reject_key!(name not on "dynamic enums" only on "their variants");
869 reject_key!(exhaustive flag not on "dynamic enums" only on "name-switched enums");
870 Ok(Self::Dynamic(DynamicEnum::new(variant_iter)?))
871 }
872 }
873
874 fn xml_name_matcher(&self) -> Result<XmlNameMatcher> {
876 match self {
877 Self::NameSwitched(ref inner) => inner.xml_name_matcher(),
878 Self::AttributeSwitched(ref inner) => inner.xml_name_matcher(),
879 Self::Dynamic(ref inner) => inner.xml_name_matcher(),
880 }
881 }
882
883 fn make_from_events_statemachine(
885 &self,
886 generics: &mut GenericsInfo,
887 target_ty_ident: &Ident,
888 state_ty_ident: &Ident,
889 ) -> Result<FromEventsStateMachine> {
890 match self {
891 Self::NameSwitched(ref inner) => {
892 inner.make_from_events_statemachine(generics, target_ty_ident, state_ty_ident)
893 }
894 Self::AttributeSwitched(ref inner) => {
895 inner.make_from_events_statemachine(generics, target_ty_ident, state_ty_ident)
896 }
897 Self::Dynamic(ref inner) => {
898 inner.make_from_events_statemachine(generics, target_ty_ident, state_ty_ident)
899 }
900 }
901 }
902
903 fn make_as_item_iter_statemachine(
905 &self,
906 generics: &mut GenericsInfo,
907 target_ty_ident: &Ident,
908 state_ty_ident: &Ident,
909 item_iter_ty_lifetime: &Lifetime,
910 ) -> Result<AsItemsStateMachine> {
911 match self {
912 Self::NameSwitched(ref inner) => inner.make_as_item_iter_statemachine(
913 generics,
914 target_ty_ident,
915 state_ty_ident,
916 item_iter_ty_lifetime,
917 ),
918 Self::AttributeSwitched(ref inner) => inner.make_as_item_iter_statemachine(
919 generics,
920 target_ty_ident,
921 state_ty_ident,
922 item_iter_ty_lifetime,
923 ),
924 Self::Dynamic(ref inner) => inner.make_as_item_iter_statemachine(
925 generics,
926 target_ty_ident,
927 state_ty_ident,
928 item_iter_ty_lifetime,
929 ),
930 }
931 }
932}
933
934pub(crate) struct EnumDef {
936 inner: EnumInner,
938
939 target_ty_ident: Ident,
941
942 builder_ty_ident: Ident,
944
945 item_iter_ty_ident: Ident,
947
948 debug: bool,
950
951 deserialize_callback: Option<Path>,
953}
954
955impl EnumDef {
956 pub(crate) fn new<'x, I: IntoIterator<Item = &'x Variant>>(
958 ident: &Ident,
959 mut meta: XmlCompoundMeta,
960 variant_iter: I,
961 ) -> Result<Self> {
962 let builder_ty_ident = match meta.builder.take() {
963 Some(v) => v,
964 None => quote::format_ident!("{}FromXmlBuilder", ident.to_string()),
965 };
966
967 let item_iter_ty_ident = match meta.iterator.take() {
968 Some(v) => v,
969 None => quote::format_ident!("{}AsXmlIterator", ident.to_string()),
970 };
971
972 let debug = meta.debug.take().is_set();
973 let deserialize_callback = meta.deserialize_callback.take();
974
975 Ok(Self {
976 inner: EnumInner::new(meta, variant_iter)?,
977 target_ty_ident: ident.clone(),
978 builder_ty_ident,
979 item_iter_ty_ident,
980 debug,
981 deserialize_callback,
982 })
983 }
984}
985
986impl ItemDef for EnumDef {
987 fn make_from_events_builder(
988 &self,
989 vis: &Visibility,
990 generics: &mut GenericsInfo,
991 name_ident: &Ident,
992 attrs_ident: &Ident,
993 ) -> Result<FromXmlParts> {
994 let target_ty_ident = &self.target_ty_ident;
995 let builder_ty_ident = &self.builder_ty_ident;
996 let state_ty_ident = quote::format_ident!("{}State", builder_ty_ident);
997
998 let defs = self
999 .inner
1000 .make_from_events_statemachine(generics, target_ty_ident, &state_ty_ident)?
1001 .render(
1002 vis,
1003 generics,
1004 builder_ty_ident,
1005 &state_ty_ident,
1006 &generics.ty_with_arguments(target_ty_ident.clone()),
1007 self.deserialize_callback.as_ref(),
1008 )?;
1009
1010 Ok(FromXmlParts {
1011 defs,
1012 from_events_body: quote! {
1013 #builder_ty_ident::new(#name_ident, #attrs_ident, ctx)
1014 },
1015 builder_ty: generics.ty_with_arguments(builder_ty_ident.clone()),
1016 name_matcher: self.inner.xml_name_matcher()?,
1017 })
1018 }
1019
1020 fn make_as_xml_iter(
1021 &self,
1022 vis: &Visibility,
1023 generics: &mut GenericsInfo,
1024 ) -> Result<AsXmlParts> {
1025 let target_ty_ident = &self.target_ty_ident;
1026 let target_ty = generics.ty_with_arguments(target_ty_ident.clone());
1027 let item_iter_ty_ident = &self.item_iter_ty_ident;
1028 let item_iter_ty_lifetime = Lifetime {
1029 apostrophe: Span::call_site(),
1030 ident: Ident::new("xso_proc_as_xml_iter_lifetime", Span::call_site()),
1031 };
1032 let mut inner_generics = generics.subscope();
1033 inner_generics.insert_lifetime(&item_iter_ty_lifetime);
1034 let state_ty_ident = quote::format_ident!("{}State", item_iter_ty_ident);
1035
1036 let defs = self
1037 .inner
1038 .make_as_item_iter_statemachine(
1039 &mut inner_generics,
1040 target_ty_ident,
1041 &state_ty_ident,
1042 &item_iter_ty_lifetime,
1043 )?
1044 .render(
1045 vis,
1046 &inner_generics,
1047 &ref_ty(target_ty, item_iter_ty_lifetime.clone()),
1048 &state_ty_ident,
1049 &item_iter_ty_lifetime,
1050 item_iter_ty_ident,
1051 )?;
1052
1053 let item_iter_ty = inner_generics.ty_with_arguments(item_iter_ty_ident.clone());
1059 generics.extend_bounds(inner_generics.into_new_bounds());
1060
1061 Ok(AsXmlParts {
1062 defs,
1063 as_xml_iter_body: quote! {
1064 #item_iter_ty_ident::new(self)
1065 },
1066 item_iter_ty,
1067 item_iter_ty_lifetime,
1068 })
1069 }
1070
1071 fn debug(&self) -> bool {
1072 self.debug
1073 }
1074}