1use crate::ast::{Pattern, QName, Schema};
7use crate::codegen::CodegenConfig;
8use std::collections::{HashMap, HashSet};
9use std::fmt::Write;
10
11pub fn generate_parsers(schema: &Schema, config: &CodegenConfig) -> String {
13 let mut g = ParserGenerator::new(schema, config);
14 g.run()
15}
16
17#[derive(Debug, Clone, Copy, PartialEq)]
19enum ParseStrategy {
20 FromXml,
22 TextFromStr,
24 TextString,
26 TextHexBinary,
28 TextBase64Binary,
30}
31
32struct ParserGenerator<'a> {
33 schema: &'a Schema,
34 config: &'a CodegenConfig,
35 output: String,
36 definitions: HashMap<&'a str, &'a Pattern>,
37 generated_names: HashSet<String>,
39}
40
41impl<'a> ParserGenerator<'a> {
42 fn new(schema: &'a Schema, config: &'a CodegenConfig) -> Self {
43 let definitions: HashMap<&str, &Pattern> = schema
44 .definitions
45 .iter()
46 .map(|d| (d.name.as_str(), &d.pattern))
47 .collect();
48
49 Self {
50 schema,
51 config,
52 output: String::new(),
53 definitions,
54 generated_names: HashSet::new(),
55 }
56 }
57
58 fn run(&mut self) -> String {
59 self.write_header();
60
61 for def in &self.schema.definitions {
63 if !def.name.contains("_ST_") && !self.is_simple_type(&def.pattern) {
64 if self.is_inline_attribute_ref(&def.name, &def.pattern) {
66 continue;
67 }
68 let rust_name = self.to_rust_type_name(&def.name);
70 if !self.generated_names.insert(rust_name) {
71 continue;
72 }
73 if def.name.contains("_EG_") && self.is_element_choice(&def.pattern) {
74 if let Some(code) = self.gen_element_group_parser(def) {
76 self.output.push_str(&code);
77 self.output.push('\n');
78 }
79 } else if !self.is_type_alias(&def.pattern) {
80 if let Some(code) = self.gen_struct_parser(def) {
82 self.output.push_str(&code);
83 self.output.push('\n');
84 }
85 }
86 }
87 }
88
89 std::mem::take(&mut self.output)
90 }
91
92 fn is_type_alias(&self, pattern: &Pattern) -> bool {
101 match pattern {
102 Pattern::Element { .. } => true,
104 Pattern::Datatype { .. } => true,
106 Pattern::Ref(name) => {
108 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
109 self.is_simple_type(def_pattern)
111 || self.is_type_alias(def_pattern)
113 } else {
114 false
117 }
118 }
119 _ => false,
120 }
121 }
122
123 fn is_inline_attribute_ref(&self, name: &str, pattern: &Pattern) -> bool {
126 !name.contains("_CT_") && matches!(pattern, Pattern::Attribute { .. })
127 }
128
129 fn write_header(&mut self) {
130 writeln!(self.output, "// Event-based parsers for generated types.").unwrap();
131 writeln!(
132 self.output,
133 "// ~3x faster than serde-based deserialization."
134 )
135 .unwrap();
136 writeln!(self.output).unwrap();
137 writeln!(self.output, "#![allow(unused_variables)]").unwrap();
138 writeln!(self.output, "#![allow(unused_imports)]").unwrap();
139 writeln!(self.output, "#![allow(clippy::single_match)]").unwrap();
140 writeln!(self.output, "#![allow(clippy::match_single_binding)]").unwrap();
141 writeln!(self.output, "#![allow(clippy::manual_is_multiple_of)]").unwrap();
142 writeln!(self.output).unwrap();
143 writeln!(self.output, "use super::generated::*;").unwrap();
144 for import in &self.config.cross_crate_imports {
146 writeln!(self.output, "use {};", import).unwrap();
147 }
148 writeln!(self.output, "use quick_xml::Reader;").unwrap();
149 writeln!(self.output, "use quick_xml::events::{{Event, BytesStart}};").unwrap();
150 writeln!(self.output, "use std::io::BufRead;").unwrap();
151 writeln!(self.output, "pub use ooxml_xml::{{FromXml, ParseError}};").unwrap();
153 writeln!(self.output, "#[cfg(feature = \"extra-children\")]").unwrap();
154 writeln!(
155 self.output,
156 "use ooxml_xml::{{PositionedNode, RawXmlElement, RawXmlNode}};"
157 )
158 .unwrap();
159 writeln!(self.output).unwrap();
160 writeln!(self.output, "#[allow(dead_code)]").unwrap();
162 writeln!(self.output, "/// Skip an element and all its children.").unwrap();
163 writeln!(
164 self.output,
165 "fn skip_element<R: BufRead>(reader: &mut Reader<R>) -> Result<(), ParseError> {{"
166 )
167 .unwrap();
168 writeln!(self.output, " let mut depth = 1u32;").unwrap();
169 writeln!(self.output, " let mut buf = Vec::new();").unwrap();
170 writeln!(self.output, " loop {{").unwrap();
171 writeln!(
172 self.output,
173 " match reader.read_event_into(&mut buf)? {{"
174 )
175 .unwrap();
176 writeln!(self.output, " Event::Start(_) => depth += 1,").unwrap();
177 writeln!(self.output, " Event::End(_) => {{").unwrap();
178 writeln!(self.output, " depth -= 1;").unwrap();
179 writeln!(self.output, " if depth == 0 {{ break; }}").unwrap();
180 writeln!(self.output, " }}").unwrap();
181 writeln!(self.output, " Event::Eof => break,").unwrap();
182 writeln!(self.output, " _ => {{}}").unwrap();
183 writeln!(self.output, " }}").unwrap();
184 writeln!(self.output, " buf.clear();").unwrap();
185 writeln!(self.output, " }}").unwrap();
186 writeln!(self.output, " Ok(())").unwrap();
187 writeln!(self.output, "}}").unwrap();
188 writeln!(self.output).unwrap();
189 writeln!(self.output, "#[allow(dead_code)]").unwrap();
191 writeln!(
192 self.output,
193 "/// Read the text content of an element until its end tag."
194 )
195 .unwrap();
196 writeln!(self.output, "fn read_text_content<R: BufRead>(reader: &mut Reader<R>) -> Result<String, ParseError> {{").unwrap();
197 writeln!(self.output, " let mut text = String::new();").unwrap();
198 writeln!(self.output, " let mut buf = Vec::new();").unwrap();
199 writeln!(self.output, " loop {{").unwrap();
200 writeln!(
201 self.output,
202 " match reader.read_event_into(&mut buf)? {{"
203 )
204 .unwrap();
205 writeln!(
206 self.output,
207 " Event::Text(e) => text.push_str(&e.decode().unwrap_or_default()),"
208 )
209 .unwrap();
210 writeln!(
211 self.output,
212 " Event::CData(e) => text.push_str(&e.decode().unwrap_or_default()),"
213 )
214 .unwrap();
215 writeln!(self.output, " Event::End(_) => break,").unwrap();
216 writeln!(self.output, " Event::Eof => break,").unwrap();
217 writeln!(self.output, " _ => {{}}").unwrap();
218 writeln!(self.output, " }}").unwrap();
219 writeln!(self.output, " buf.clear();").unwrap();
220 writeln!(self.output, " }}").unwrap();
221 writeln!(self.output, " Ok(text)").unwrap();
222 writeln!(self.output, "}}").unwrap();
223 writeln!(self.output).unwrap();
224 writeln!(self.output, "#[allow(dead_code)]").unwrap();
226 writeln!(self.output, "/// Decode a hex string to bytes.").unwrap();
227 writeln!(self.output, "fn decode_hex(s: &str) -> Option<Vec<u8>> {{").unwrap();
228 writeln!(self.output, " let s = s.trim();").unwrap();
229 writeln!(self.output, " if s.len() % 2 != 0 {{ return None; }}").unwrap();
230 writeln!(self.output, " (0..s.len())").unwrap();
231 writeln!(self.output, " .step_by(2)").unwrap();
232 writeln!(
233 self.output,
234 " .map(|i| u8::from_str_radix(&s[i..i + 2], 16).ok())"
235 )
236 .unwrap();
237 writeln!(self.output, " .collect()").unwrap();
238 writeln!(self.output, "}}").unwrap();
239 writeln!(self.output).unwrap();
240
241 writeln!(self.output, "#[allow(dead_code)]").unwrap();
243 writeln!(self.output, "/// Decode a base64 string to bytes.").unwrap();
244 writeln!(
245 self.output,
246 "fn decode_base64(s: &str) -> Option<Vec<u8>> {{"
247 )
248 .unwrap();
249 writeln!(self.output, " use base64::Engine;").unwrap();
250 writeln!(
251 self.output,
252 " base64::engine::general_purpose::STANDARD.decode(s.trim()).ok()"
253 )
254 .unwrap();
255 writeln!(self.output, "}}").unwrap();
256 writeln!(self.output).unwrap();
257 }
258
259 fn is_simple_type(&self, pattern: &Pattern) -> bool {
260 match pattern {
261 Pattern::Choice(variants) => variants
262 .iter()
263 .all(|v| matches!(v, Pattern::StringLiteral(_))),
264 Pattern::StringLiteral(_) => true,
265 Pattern::Datatype { .. } => true,
266 Pattern::List(_) => true,
267 Pattern::Ref(name) => self
268 .definitions
269 .get(name.as_str())
270 .is_some_and(|p| self.is_simple_type(p)),
271 _ => false,
272 }
273 }
274
275 fn is_element_choice(&self, pattern: &Pattern) -> bool {
276 match pattern {
277 Pattern::Choice(variants) => variants.iter().any(Self::is_direct_element_variant),
278 _ => false,
279 }
280 }
281
282 fn is_direct_element_variant(pattern: &Pattern) -> bool {
283 match pattern {
284 Pattern::Element { .. } => true,
285 Pattern::Optional(inner) | Pattern::ZeroOrMore(inner) | Pattern::OneOrMore(inner) => {
286 Self::is_direct_element_variant(inner)
287 }
288 _ => false,
289 }
290 }
291
292 fn has_xml_children_pattern(&self, pattern: &Pattern) -> bool {
294 match pattern {
295 Pattern::Empty => false,
296 Pattern::Attribute { .. } => false,
297 Pattern::Element { .. } => true,
298 Pattern::Ref(name) => {
299 if name.contains("_AG_") {
300 return false;
301 }
302 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
303 self.has_xml_children_pattern(def_pattern)
304 } else {
305 true
306 }
307 }
308 Pattern::Sequence(items) | Pattern::Interleave(items) | Pattern::Choice(items) => {
309 items.iter().any(|i| self.has_xml_children_pattern(i))
310 }
311 Pattern::Optional(inner)
312 | Pattern::ZeroOrMore(inner)
313 | Pattern::OneOrMore(inner)
314 | Pattern::Group(inner)
315 | Pattern::Mixed(inner) => self.has_xml_children_pattern(inner),
316 Pattern::Text => true,
317 _ => false,
318 }
319 }
320
321 fn has_xml_attr_pattern(&self, pattern: &Pattern) -> bool {
323 match pattern {
324 Pattern::Attribute { .. } => true,
325 Pattern::Ref(name) if name.contains("_AG_") => true,
326 Pattern::Ref(name) => {
327 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
328 self.has_xml_attr_pattern(def_pattern)
329 } else {
330 false
331 }
332 }
333 Pattern::Sequence(items) | Pattern::Interleave(items) | Pattern::Choice(items) => {
334 items.iter().any(|i| self.has_xml_attr_pattern(i))
335 }
336 Pattern::Optional(inner)
337 | Pattern::ZeroOrMore(inner)
338 | Pattern::OneOrMore(inner)
339 | Pattern::Group(inner) => self.has_xml_attr_pattern(inner),
340 _ => false,
341 }
342 }
343
344 fn eg_ref_to_field_name(&self, name: &str) -> String {
345 let spec_name = strip_namespace_prefix(name);
346 let short = spec_name.strip_prefix("EG_").unwrap_or(spec_name);
347 if let Some(mappings) = &self.config.name_mappings
349 && let Some(mapped) = mappings.resolve_field(&self.config.module_name, short)
350 {
351 return mapped.to_string();
352 }
353 to_snake_case(short)
354 }
355
356 fn is_eg_content_field(&self, field: &Field) -> bool {
357 if let Pattern::Ref(name) = &field.pattern
358 && name.contains("_EG_")
359 && let Some(pattern) = self.definitions.get(name.as_str())
360 {
361 return self.is_element_choice(pattern);
362 }
363 false
364 }
365
366 fn collect_element_variant_names(
368 &self,
369 pattern: &Pattern,
370 names: &mut Vec<String>,
371 visited: &mut std::collections::HashSet<String>,
372 ) {
373 match pattern {
374 Pattern::Element { name, .. } => {
375 names.push(name.local.clone());
376 }
377 Pattern::Optional(inner)
378 | Pattern::ZeroOrMore(inner)
379 | Pattern::OneOrMore(inner)
380 | Pattern::Group(inner) => {
381 self.collect_element_variant_names(inner, names, visited);
382 }
383 Pattern::Ref(name) if name.contains("_EG_") && visited.insert(name.clone()) => {
384 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
385 self.collect_element_variant_names(def_pattern, names, visited);
386 }
387 }
388 Pattern::Choice(items) | Pattern::Sequence(items) | Pattern::Interleave(items) => {
389 for item in items {
390 self.collect_element_variant_names(item, names, visited);
391 }
392 }
393 _ => {}
394 }
395 }
396
397 fn collect_eg_variants(
400 &self,
401 pattern: &Pattern,
402 variants: &mut Vec<(String, String, bool, bool)>,
403 visited: &mut std::collections::HashSet<String>,
404 ) {
405 match pattern {
406 Pattern::Element { name, pattern } => {
407 let (rust_type, needs_box) = self.pattern_to_rust_type(pattern, false);
409 let (actual_type, type_alias_has_box) =
412 self.resolve_from_xml_type_with_box(pattern);
413 let inner_type = actual_type.unwrap_or(rust_type);
414 variants.push((
415 name.local.clone(),
416 inner_type,
417 needs_box,
418 type_alias_has_box,
419 ));
420 }
421 Pattern::Optional(inner)
422 | Pattern::ZeroOrMore(inner)
423 | Pattern::OneOrMore(inner)
424 | Pattern::Group(inner) => {
425 self.collect_eg_variants(inner, variants, visited);
426 }
427 Pattern::Ref(name) if name.contains("_EG_") && visited.insert(name.clone()) => {
428 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
429 self.collect_eg_variants(def_pattern, variants, visited);
430 }
431 }
432 Pattern::Choice(items) | Pattern::Sequence(items) | Pattern::Interleave(items) => {
433 for item in items {
434 self.collect_eg_variants(item, variants, visited);
435 }
436 }
437 _ => {}
438 }
439 }
440
441 fn gen_element_group_parser(&self, def: &crate::ast::Definition) -> Option<String> {
442 let rust_name = self.to_rust_type_name(&def.name);
443
444 let Pattern::Choice(variants) = &def.pattern else {
445 return None;
446 };
447
448 let mut element_variants = Vec::new();
450 let mut visited = std::collections::HashSet::new();
451 visited.insert(def.name.clone());
452 for v in variants {
453 self.collect_eg_variants(v, &mut element_variants, &mut visited);
454 }
455 let mut seen = std::collections::HashSet::new();
457 element_variants.retain(|(name, _, _, _)| seen.insert(name.clone()));
458
459 if element_variants.is_empty() {
460 return None;
461 }
462
463 let mut code = String::new();
464 writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
465 writeln!(
466 code,
467 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
468 )
469 .unwrap();
470 writeln!(code, " let tag = start_tag.local_name();").unwrap();
471 writeln!(code, " match tag.as_ref() {{").unwrap();
472
473 for (xml_name, inner_type, needs_box, type_alias_has_box) in &element_variants {
474 let variant_name = self.to_rust_variant_name(xml_name);
475 writeln!(code, " b\"{}\" => {{", xml_name).unwrap();
476 writeln!(
477 code,
478 " let inner = {}::from_xml(reader, start_tag, is_empty)?;",
479 inner_type
480 )
481 .unwrap();
482 let wrap_expr = match (*needs_box, *type_alias_has_box) {
486 (true, true) => "Box::new(Box::new(inner))",
487 (true, false) => "Box::new(inner)",
488 (false, true) => "Box::new(inner)",
489 (false, false) => "inner",
490 };
491 writeln!(
492 code,
493 " Ok(Self::{}({}))",
494 variant_name, wrap_expr
495 )
496 .unwrap();
497 writeln!(code, " }}").unwrap();
498 }
499
500 writeln!(code, " _ => Err(ParseError::UnexpectedElement(").unwrap();
501 writeln!(
502 code,
503 " String::from_utf8_lossy(start_tag.name().as_ref()).into_owned()"
504 )
505 .unwrap();
506 writeln!(code, " )),").unwrap();
507 writeln!(code, " }}").unwrap();
508 writeln!(code, " }}").unwrap();
509 writeln!(code, "}}").unwrap();
510
511 Some(code)
512 }
513
514 fn gen_struct_parser(&self, def: &crate::ast::Definition) -> Option<String> {
515 let rust_name = self.to_rust_type_name(&def.name);
516 let fields = self.extract_fields(&def.pattern);
517
518 if fields.is_empty() {
519 let has_unresolved_children = self.has_xml_children_pattern(&def.pattern);
520 let has_unresolved_attrs = self.has_xml_attr_pattern(&def.pattern);
521
522 let mut code = String::new();
523 writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
524
525 if has_unresolved_children || has_unresolved_attrs {
526 writeln!(
528 code,
529 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
530 )
531 .unwrap();
532 if has_unresolved_attrs {
533 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
534 writeln!(
535 code,
536 " let mut extra_attrs = std::collections::HashMap::new();"
537 )
538 .unwrap();
539 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
540 writeln!(
541 code,
542 " for attr in start_tag.attributes().filter_map(|a| a.ok()) {{"
543 )
544 .unwrap();
545 writeln!(
546 code,
547 " let key = String::from_utf8_lossy(attr.key.as_ref()).into_owned();"
548 )
549 .unwrap();
550 writeln!(
551 code,
552 " let val = String::from_utf8_lossy(&attr.value).into_owned();"
553 )
554 .unwrap();
555 writeln!(code, " extra_attrs.insert(key, val);").unwrap();
556 writeln!(code, " }}").unwrap();
557 }
558 if has_unresolved_children {
559 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
560 writeln!(code, " let mut extra_children = Vec::new();").unwrap();
561 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
562 writeln!(code, " let mut child_idx: usize = 0;").unwrap();
563 }
564 writeln!(code, " if !is_empty {{").unwrap();
565 writeln!(code, " let mut buf = Vec::new();").unwrap();
566 writeln!(code, " loop {{").unwrap();
567 writeln!(
568 code,
569 " match reader.read_event_into(&mut buf)? {{"
570 )
571 .unwrap();
572 if has_unresolved_children {
573 writeln!(
574 code,
575 " #[cfg(feature = \"extra-children\")]"
576 )
577 .unwrap();
578 writeln!(code, " Event::Start(e) => {{").unwrap();
579 writeln!(
580 code,
581 " let elem = RawXmlElement::from_reader(reader, &e)?;"
582 )
583 .unwrap();
584 writeln!(
585 code,
586 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
587 )
588 .unwrap();
589 writeln!(code, " child_idx += 1;").unwrap();
590 writeln!(code, " }}").unwrap();
591 writeln!(
592 code,
593 " #[cfg(not(feature = \"extra-children\"))]"
594 )
595 .unwrap();
596 writeln!(
597 code,
598 " Event::Start(_) => {{ skip_element(reader)?; }}"
599 )
600 .unwrap();
601 writeln!(
602 code,
603 " #[cfg(feature = \"extra-children\")]"
604 )
605 .unwrap();
606 writeln!(code, " Event::Empty(e) => {{").unwrap();
607 writeln!(
608 code,
609 " let elem = RawXmlElement::from_empty(&e);"
610 )
611 .unwrap();
612 writeln!(
613 code,
614 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
615 )
616 .unwrap();
617 writeln!(code, " child_idx += 1;").unwrap();
618 writeln!(code, " }}").unwrap();
619 writeln!(
620 code,
621 " #[cfg(not(feature = \"extra-children\"))]"
622 )
623 .unwrap();
624 writeln!(code, " Event::Empty(_) => {{}}").unwrap();
625 } else {
626 writeln!(
627 code,
628 " Event::Start(_) => {{ skip_element(reader)?; }}"
629 )
630 .unwrap();
631 writeln!(code, " Event::Empty(_) => {{}}").unwrap();
632 }
633 writeln!(code, " Event::End(_) => break,").unwrap();
634 writeln!(code, " Event::Eof => break,").unwrap();
635 writeln!(code, " _ => {{}}").unwrap();
636 writeln!(code, " }}").unwrap();
637 writeln!(code, " buf.clear();").unwrap();
638 writeln!(code, " }}").unwrap();
639 writeln!(code, " }}").unwrap();
640 writeln!(code, " Ok(Self {{").unwrap();
641 if has_unresolved_attrs {
642 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
643 writeln!(code, " extra_attrs,").unwrap();
644 }
645 if has_unresolved_children {
646 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
647 writeln!(code, " extra_children,").unwrap();
648 }
649 writeln!(code, " }})").unwrap();
650 } else {
651 writeln!(
653 code,
654 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, _start: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
655 )
656 .unwrap();
657 writeln!(code, " if !is_empty {{").unwrap();
658 writeln!(code, " let mut buf = Vec::new();").unwrap();
659 writeln!(code, " let mut depth = 1u32;").unwrap();
660 writeln!(code, " loop {{").unwrap();
661 writeln!(
662 code,
663 " match reader.read_event_into(&mut buf)? {{"
664 )
665 .unwrap();
666 writeln!(code, " Event::Start(_) => depth += 1,").unwrap();
667 writeln!(
668 code,
669 " Event::End(_) => {{ depth -= 1; if depth == 0 {{ break; }} }}"
670 )
671 .unwrap();
672 writeln!(code, " Event::Eof => break,").unwrap();
673 writeln!(code, " _ => {{}}").unwrap();
674 writeln!(code, " }}").unwrap();
675 writeln!(code, " buf.clear();").unwrap();
676 writeln!(code, " }}").unwrap();
677 writeln!(code, " }}").unwrap();
678 writeln!(code, " Ok(Self {{}})").unwrap();
679 }
680
681 writeln!(code, " }}").unwrap();
682 writeln!(code, "}}").unwrap();
683 return Some(code);
684 }
685
686 let mut code = String::new();
687 writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
688 writeln!(
689 code,
690 " fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
691 )
692 .unwrap();
693
694 for field in &fields {
696 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
698 let base_name = base_name.trim_start_matches('_');
699 let var_name = format!("f_{}", base_name);
700
701 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
703 write!(code, " #[cfg(feature = \"{}\")] ", feature).unwrap();
704 } else {
705 write!(code, " ").unwrap();
706 }
707
708 if field.is_vec {
709 writeln!(code, "let mut {} = Vec::new();", var_name).unwrap();
710 } else if field.is_optional {
711 writeln!(code, "let mut {} = None;", var_name).unwrap();
712 } else {
713 let (rust_type, needs_box) = self.pattern_to_rust_type(&field.pattern, false);
715 let full_type = if needs_box {
716 format!("Box<{}>", rust_type)
717 } else {
718 rust_type
719 };
720 writeln!(code, "let mut {}: Option<{}> = None;", var_name, full_type).unwrap();
721 }
722 }
723
724 let attr_fields: Vec<_> = fields.iter().filter(|f| f.is_attribute).collect();
726 let has_attrs = !attr_fields.is_empty();
727 let elem_fields: Vec<_> = fields
728 .iter()
729 .filter(|f| !f.is_attribute && !f.is_text_content)
730 .collect();
731 let text_fields: Vec<_> = fields.iter().filter(|f| f.is_text_content).collect();
732 let has_children = !elem_fields.is_empty();
733 let has_parsing_loop = has_children || !text_fields.is_empty();
734 if has_attrs {
735 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
737 writeln!(
738 code,
739 " let mut extra_attrs = std::collections::HashMap::new();"
740 )
741 .unwrap();
742 }
743 if has_parsing_loop {
744 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
746 writeln!(code, " let mut extra_children = Vec::new();").unwrap();
747 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
748 writeln!(code, " let mut child_idx: usize = 0;").unwrap();
749 }
750 if has_attrs || has_parsing_loop {
751 writeln!(code).unwrap();
752 }
753 if has_attrs {
754 writeln!(code, " // Parse attributes").unwrap();
755 writeln!(
756 code,
757 " for attr in start_tag.attributes().filter_map(|a| a.ok()) {{"
758 )
759 .unwrap();
760 writeln!(
761 code,
762 " let val = String::from_utf8_lossy(&attr.value);"
763 )
764 .unwrap();
765 writeln!(code, " match attr.key.local_name().as_ref() {{").unwrap();
766 for field in &attr_fields {
767 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
768 let base_name = base_name.trim_start_matches('_');
769 let var_name = format!("f_{}", base_name);
770 let parse_expr = self.gen_attr_parse_expr(&field.pattern);
771
772 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
774 writeln!(code, " #[cfg(feature = \"{}\")]", feature).unwrap();
775 }
776 writeln!(code, " b\"{}\" => {{", field.xml_name).unwrap();
777 writeln!(code, " {} = {};", var_name, parse_expr).unwrap();
778 writeln!(code, " }}").unwrap();
779 }
780 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
782 writeln!(code, " unknown => {{").unwrap();
783 writeln!(
784 code,
785 " let key = String::from_utf8_lossy(attr.key.as_ref()).into_owned();"
786 )
787 .unwrap();
788 writeln!(
789 code,
790 " extra_attrs.insert(key, val.into_owned());"
791 )
792 .unwrap();
793 writeln!(code, " }}").unwrap();
794 writeln!(
795 code,
796 " #[cfg(not(feature = \"extra-attrs\"))]"
797 )
798 .unwrap();
799 writeln!(code, " _ => {{}}").unwrap();
800 writeln!(code, " }}").unwrap();
801 writeln!(code, " }}").unwrap();
802 }
803
804 if has_parsing_loop {
806 writeln!(code).unwrap();
807 writeln!(code, " // Parse child elements").unwrap();
808 writeln!(code, " if !is_empty {{").unwrap();
809 writeln!(code, " let mut buf = Vec::new();").unwrap();
810 writeln!(code, " loop {{").unwrap();
811 writeln!(
812 code,
813 " match reader.read_event_into(&mut buf)? {{"
814 )
815 .unwrap();
816 writeln!(code, " Event::Start(e) => {{").unwrap();
817 writeln!(
818 code,
819 " match e.local_name().as_ref() {{"
820 )
821 .unwrap();
822
823 let mut matched_names = std::collections::HashSet::new();
825 for field in &elem_fields {
826 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
827 let base_name = base_name.trim_start_matches('_');
828 let var_name = format!("f_{}", base_name);
829 let parse_expr = self.gen_element_parse_code(field, false);
830
831 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
833 writeln!(
834 code,
835 " #[cfg(feature = \"{}\")]",
836 feature
837 )
838 .unwrap();
839 }
840 if self.is_eg_content_field(field) {
841 let mut variant_names = Vec::new();
843 let mut visited = std::collections::HashSet::new();
844 if let Some(def_pattern) = self.definitions.get(field.xml_name.as_str()) {
845 self.collect_element_variant_names(
846 def_pattern,
847 &mut variant_names,
848 &mut visited,
849 );
850 }
851 variant_names.retain(|n| matched_names.insert(n.clone()));
852 if !variant_names.is_empty() {
853 let arms: Vec<_> = variant_names
854 .iter()
855 .map(|n| format!("b\"{}\"", n))
856 .collect();
857 writeln!(
858 code,
859 " {} => {{",
860 arms.join(" | ")
861 )
862 .unwrap();
863 } else {
864 continue;
866 }
867 } else {
868 matched_names.insert(field.xml_name.clone());
869 writeln!(
870 code,
871 " b\"{}\" => {{",
872 field.xml_name
873 )
874 .unwrap();
875 }
876 if field.is_vec {
877 writeln!(
878 code,
879 " {}.push({});",
880 var_name, parse_expr
881 )
882 .unwrap();
883 } else {
884 writeln!(
885 code,
886 " {} = Some({});",
887 var_name, parse_expr
888 )
889 .unwrap();
890 }
891 writeln!(
892 code,
893 " #[cfg(feature = \"extra-children\")]"
894 )
895 .unwrap();
896 writeln!(
897 code,
898 " {{ child_idx += 1; }}"
899 )
900 .unwrap();
901 writeln!(code, " }}").unwrap();
902 }
903
904 writeln!(
906 code,
907 " #[cfg(feature = \"extra-children\")]"
908 )
909 .unwrap();
910 writeln!(code, " _ => {{").unwrap();
911 writeln!(
912 code,
913 " // Capture unknown element for roundtrip"
914 )
915 .unwrap();
916 writeln!(code, " let elem = RawXmlElement::from_reader(reader, &e)?;").unwrap();
917 writeln!(
918 code,
919 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
920 )
921 .unwrap();
922 writeln!(code, " child_idx += 1;").unwrap();
923 writeln!(code, " }}").unwrap();
924 writeln!(
925 code,
926 " #[cfg(not(feature = \"extra-children\"))]"
927 )
928 .unwrap();
929 writeln!(code, " _ => {{").unwrap();
930 writeln!(
931 code,
932 " // Skip unknown element"
933 )
934 .unwrap();
935 writeln!(
936 code,
937 " skip_element(reader)?;"
938 )
939 .unwrap();
940 writeln!(code, " }}").unwrap();
941 writeln!(code, " }}").unwrap();
942 writeln!(code, " }}").unwrap();
943 writeln!(code, " Event::Empty(e) => {{").unwrap();
944 writeln!(
945 code,
946 " match e.local_name().as_ref() {{"
947 )
948 .unwrap();
949
950 let mut matched_names_empty = std::collections::HashSet::new();
952 for field in &elem_fields {
953 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
954 let base_name = base_name.trim_start_matches('_');
955 let var_name = format!("f_{}", base_name);
956 let parse_expr = self.gen_element_parse_code(field, true);
957
958 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
960 writeln!(
961 code,
962 " #[cfg(feature = \"{}\")]",
963 feature
964 )
965 .unwrap();
966 }
967 if self.is_eg_content_field(field) {
968 let mut variant_names = Vec::new();
970 let mut visited = std::collections::HashSet::new();
971 if let Some(def_pattern) = self.definitions.get(field.xml_name.as_str()) {
972 self.collect_element_variant_names(
973 def_pattern,
974 &mut variant_names,
975 &mut visited,
976 );
977 }
978 variant_names.retain(|n| matched_names_empty.insert(n.clone()));
979 if !variant_names.is_empty() {
980 let arms: Vec<_> = variant_names
981 .iter()
982 .map(|n| format!("b\"{}\"", n))
983 .collect();
984 writeln!(
985 code,
986 " {} => {{",
987 arms.join(" | ")
988 )
989 .unwrap();
990 } else {
991 continue;
993 }
994 } else {
995 matched_names_empty.insert(field.xml_name.clone());
996 writeln!(
997 code,
998 " b\"{}\" => {{",
999 field.xml_name
1000 )
1001 .unwrap();
1002 }
1003 if field.is_vec {
1004 writeln!(
1005 code,
1006 " {}.push({});",
1007 var_name, parse_expr
1008 )
1009 .unwrap();
1010 } else {
1011 writeln!(
1012 code,
1013 " {} = Some({});",
1014 var_name, parse_expr
1015 )
1016 .unwrap();
1017 }
1018 writeln!(
1019 code,
1020 " #[cfg(feature = \"extra-children\")]"
1021 )
1022 .unwrap();
1023 writeln!(
1024 code,
1025 " {{ child_idx += 1; }}"
1026 )
1027 .unwrap();
1028 writeln!(code, " }}").unwrap();
1029 }
1030
1031 writeln!(
1033 code,
1034 " #[cfg(feature = \"extra-children\")]"
1035 )
1036 .unwrap();
1037 writeln!(code, " _ => {{").unwrap();
1038 writeln!(
1039 code,
1040 " // Capture unknown empty element for roundtrip"
1041 )
1042 .unwrap();
1043 writeln!(
1044 code,
1045 " let elem = RawXmlElement::from_empty(&e);"
1046 )
1047 .unwrap();
1048 writeln!(
1049 code,
1050 " extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
1051 )
1052 .unwrap();
1053 writeln!(code, " child_idx += 1;").unwrap();
1054 writeln!(code, " }}").unwrap();
1055 writeln!(
1056 code,
1057 " #[cfg(not(feature = \"extra-children\"))]"
1058 )
1059 .unwrap();
1060 writeln!(code, " _ => {{}}").unwrap();
1061 writeln!(code, " }}").unwrap();
1062 writeln!(code, " }}").unwrap();
1063
1064 if !text_fields.is_empty() {
1066 writeln!(code, " Event::Text(e) => {{").unwrap();
1067 for field in &text_fields {
1068 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1069 let base_name = base_name.trim_start_matches('_');
1070 let var_name = format!("f_{}", base_name);
1071 writeln!(
1072 code,
1073 " {} = Some(e.decode().unwrap_or_default().into_owned());",
1074 var_name
1075 ).unwrap();
1076 }
1077 writeln!(code, " }}").unwrap();
1078 }
1079
1080 writeln!(code, " Event::End(_) => break,").unwrap();
1081 writeln!(code, " Event::Eof => break,").unwrap();
1082 writeln!(code, " _ => {{}}").unwrap();
1083 writeln!(code, " }}").unwrap();
1084 writeln!(code, " buf.clear();").unwrap();
1085 writeln!(code, " }}").unwrap();
1086 writeln!(code, " }}").unwrap();
1087 } else {
1088 writeln!(code).unwrap();
1090 writeln!(code, " if !is_empty {{").unwrap();
1091 writeln!(code, " let mut buf = Vec::new();").unwrap();
1092 writeln!(code, " loop {{").unwrap();
1093 writeln!(
1094 code,
1095 " match reader.read_event_into(&mut buf)? {{"
1096 )
1097 .unwrap();
1098 writeln!(code, " Event::End(_) => break,").unwrap();
1099 writeln!(code, " Event::Eof => break,").unwrap();
1100 writeln!(code, " _ => {{}}").unwrap();
1101 writeln!(code, " }}").unwrap();
1102 writeln!(code, " buf.clear();").unwrap();
1103 writeln!(code, " }}").unwrap();
1104 writeln!(code, " }}").unwrap();
1105 }
1106
1107 writeln!(code).unwrap();
1109 writeln!(code, " Ok(Self {{").unwrap();
1110 for field in &fields {
1111 let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1112 let base_name = base_name.trim_start_matches('_');
1113 let var_name = format!("f_{}", base_name);
1114
1115 if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
1117 writeln!(code, " #[cfg(feature = \"{}\")]", feature).unwrap();
1118 }
1119
1120 let eg_needs_option =
1123 self.is_eg_content_field(field) && !field.is_optional && !field.is_vec;
1124
1125 if field.is_optional || field.is_vec || eg_needs_option {
1126 writeln!(code, " {}: {},", field.name, var_name).unwrap();
1127 } else {
1128 writeln!(
1130 code,
1131 " {}: {}.ok_or_else(|| ParseError::MissingAttribute(\"{}\".to_string()))?,",
1132 field.name, var_name, field.xml_name
1133 )
1134 .unwrap();
1135 }
1136 }
1137 if has_attrs {
1139 writeln!(code, " #[cfg(feature = \"extra-attrs\")]").unwrap();
1140 writeln!(code, " extra_attrs,").unwrap();
1141 }
1142 if has_parsing_loop {
1144 writeln!(code, " #[cfg(feature = \"extra-children\")]").unwrap();
1145 writeln!(code, " extra_children,").unwrap();
1146 }
1147 writeln!(code, " }})").unwrap();
1148 writeln!(code, " }}").unwrap();
1149 writeln!(code, "}}").unwrap();
1150
1151 Some(code)
1152 }
1153
1154 fn gen_attr_parse_expr(&self, pattern: &Pattern) -> String {
1155 match pattern {
1156 Pattern::Datatype { library, name, .. } if library == "xsd" => match name.as_str() {
1157 "boolean" => "Some(val == \"true\" || val == \"1\")".to_string(),
1158 "integer" | "int" | "long" | "short" | "byte" => "val.parse().ok()".to_string(),
1159 "unsignedInt" | "unsignedLong" | "unsignedShort" | "unsignedByte" => {
1160 "val.parse().ok()".to_string()
1161 }
1162 "double" | "float" | "decimal" => "val.parse().ok()".to_string(),
1163 "hexBinary" => "decode_hex(&val)".to_string(),
1164 "base64Binary" => "decode_base64(&val)".to_string(),
1165 _ => "Some(val.into_owned())".to_string(),
1166 },
1167 Pattern::Ref(name) => {
1168 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1170 return self.gen_attr_parse_expr(def_pattern);
1171 }
1172 if name.contains("_ST_") {
1174 "val.parse().ok()".to_string()
1175 } else {
1176 "Some(val.into_owned())".to_string()
1177 }
1178 }
1179 Pattern::Choice(variants)
1181 if variants
1182 .iter()
1183 .all(|v| matches!(v, Pattern::StringLiteral(_))) =>
1184 {
1185 "val.parse().ok()".to_string()
1186 }
1187 _ => "Some(val.into_owned())".to_string(),
1188 }
1189 }
1190
1191 fn extract_fields(&self, pattern: &Pattern) -> Vec<Field> {
1192 let mut fields = Vec::new();
1193 self.collect_fields(pattern, &mut fields, false);
1194 let mut seen = std::collections::HashSet::new();
1195 fields.retain(|f| seen.insert(f.name.clone()));
1196 fields
1197 }
1198
1199 fn collect_fields(&self, pattern: &Pattern, fields: &mut Vec<Field>, is_optional: bool) {
1200 match pattern {
1201 Pattern::Attribute { name, pattern } => {
1202 fields.push(Field {
1203 name: self.qname_to_field_name(name),
1204 xml_name: name.local.clone(),
1205 xml_prefix: name.prefix.clone(),
1206 pattern: pattern.as_ref().clone(),
1207 is_optional,
1208 is_attribute: true,
1209 is_vec: false,
1210 is_text_content: false,
1211 });
1212 }
1213 Pattern::Element { name, pattern } => {
1214 if name.local == "_any" {
1216 return;
1217 }
1218 fields.push(Field {
1219 name: self.qname_to_field_name(name),
1220 xml_name: name.local.clone(),
1221 xml_prefix: name.prefix.clone(),
1222 pattern: pattern.as_ref().clone(),
1223 is_optional,
1224 is_attribute: false,
1225 is_vec: false,
1226 is_text_content: false,
1227 });
1228 }
1229 Pattern::Sequence(items) | Pattern::Interleave(items) => {
1230 for item in items {
1231 self.collect_fields(item, fields, is_optional);
1232 }
1233 }
1234 Pattern::Optional(inner) => {
1235 self.collect_fields(inner, fields, true);
1236 }
1237 Pattern::ZeroOrMore(inner) | Pattern::OneOrMore(inner) => match inner.as_ref() {
1238 Pattern::Element { name, pattern } if name.local != "_any" => {
1239 fields.push(Field {
1240 name: self.qname_to_field_name(name),
1241 xml_name: name.local.clone(),
1242 xml_prefix: name.prefix.clone(),
1243 pattern: pattern.as_ref().clone(),
1244 is_optional: false,
1245 is_attribute: false,
1246 is_vec: true,
1247 is_text_content: false,
1248 });
1249 }
1250 Pattern::Ref(name) if name.contains("_EG_") => {
1251 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1252 if self.is_element_choice(def_pattern) {
1253 fields.push(Field {
1255 name: self.eg_ref_to_field_name(name),
1256 xml_name: name.clone(),
1257 xml_prefix: None,
1258 pattern: Pattern::Ref(name.clone()),
1259 is_optional: false,
1260 is_attribute: false,
1261 is_vec: true,
1262 is_text_content: false,
1263 });
1264 } else {
1265 self.collect_fields(def_pattern, fields, true);
1267 }
1268 }
1269 }
1270 Pattern::Choice(alternatives) => {
1271 for alt in alternatives {
1273 self.collect_fields_as_vec(alt, fields);
1274 }
1275 }
1276 Pattern::Ref(_) => {
1277 self.collect_fields(inner, fields, false);
1278 }
1279 Pattern::Group(group_inner) => {
1280 if let Pattern::Choice(alternatives) = group_inner.as_ref() {
1283 for alt in alternatives {
1284 self.collect_fields_as_vec(alt, fields);
1285 }
1286 } else {
1287 self.collect_fields(group_inner, fields, false);
1288 }
1289 }
1290 _ => {}
1291 },
1292 Pattern::Group(inner) => {
1293 self.collect_fields(inner, fields, is_optional);
1294 }
1295 Pattern::Ref(name) => {
1296 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1297 if name.contains("_EG_") {
1298 if self.is_element_choice(def_pattern) {
1299 fields.push(Field {
1301 name: self.eg_ref_to_field_name(name),
1302 xml_name: name.clone(),
1303 xml_prefix: None,
1304 pattern: Pattern::Ref(name.clone()),
1305 is_optional,
1306 is_attribute: false,
1307 is_vec: false,
1308 is_text_content: false,
1309 });
1310 } else {
1311 self.collect_fields(def_pattern, fields, is_optional);
1313 }
1314 } else if name.contains("_AG_") {
1315 self.collect_fields(def_pattern, fields, is_optional);
1317 } else if self.is_string_type(def_pattern) {
1318 fields.push(Field {
1321 name: "text".to_string(),
1322 xml_name: "$text".to_string(),
1323 xml_prefix: None,
1324 pattern: Pattern::Datatype {
1325 library: "xsd".to_string(),
1326 name: "string".to_string(),
1327 params: vec![],
1328 },
1329 is_optional: true,
1330 is_attribute: false,
1331 is_vec: false,
1332 is_text_content: true,
1333 });
1334 } else {
1335 self.collect_fields(def_pattern, fields, is_optional);
1337 }
1338 }
1339 }
1340 Pattern::Choice(alternatives) => {
1341 for alt in alternatives {
1344 self.collect_fields(alt, fields, true);
1345 }
1346 }
1347 _ => {}
1348 }
1349 }
1350
1351 fn collect_fields_as_vec(&self, pattern: &Pattern, fields: &mut Vec<Field>) {
1354 match pattern {
1355 Pattern::Element {
1356 name,
1357 pattern: inner_pattern,
1358 } if name.local != "_any" => {
1359 fields.push(Field {
1360 name: self.qname_to_field_name(name),
1361 xml_name: name.local.clone(),
1362 xml_prefix: name.prefix.clone(),
1363 pattern: inner_pattern.as_ref().clone(),
1364 is_optional: false,
1365 is_attribute: false,
1366 is_vec: true,
1367 is_text_content: false,
1368 });
1369 }
1370 Pattern::Optional(inner) => {
1371 self.collect_fields(inner, fields, true);
1374 }
1375 Pattern::Group(inner) => {
1376 self.collect_fields_as_vec(inner, fields);
1377 }
1378 Pattern::Ref(name) => {
1379 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1381 if name.contains("_EG_") && self.is_element_choice(def_pattern) {
1382 fields.push(Field {
1384 name: self.eg_ref_to_field_name(name),
1385 xml_name: name.clone(),
1386 xml_prefix: None,
1387 pattern: Pattern::Ref(name.clone()),
1388 is_optional: false,
1389 is_attribute: false,
1390 is_vec: true,
1391 is_text_content: false,
1392 });
1393 } else if !name.contains("_AG_") && !name.contains("_CT_") {
1394 self.collect_fields_as_vec(def_pattern, fields);
1396 }
1397 }
1398 }
1399 _ => {}
1400 }
1401 }
1402
1403 fn is_string_type(&self, pattern: &Pattern) -> bool {
1405 match pattern {
1406 Pattern::Datatype { library, name, .. } => {
1407 library == "xsd" && (name == "string" || name == "token" || name == "NCName")
1408 }
1409 Pattern::Ref(name) => {
1410 self.definitions
1412 .get(name.as_str())
1413 .is_some_and(|p| self.is_string_type(p))
1414 }
1415 _ => false,
1416 }
1417 }
1418
1419 fn to_rust_type_name(&self, name: &str) -> String {
1420 let spec_name = strip_namespace_prefix(name);
1421 if let Some(mappings) = &self.config.name_mappings
1422 && let Some(mapped) = mappings.resolve_type(&self.config.module_name, spec_name)
1423 {
1424 return mapped.to_string();
1425 }
1426 to_pascal_case(spec_name)
1427 }
1428
1429 fn resolve_cross_crate_type(&self, name: &str) -> Option<String> {
1432 for (prefix, (crate_path, module_name)) in &self.config.cross_crate_type_prefix {
1433 if name.starts_with(prefix) {
1434 let spec_name = strip_namespace_prefix(name);
1436 let rust_type_name = if let Some(mappings) = &self.config.name_mappings
1437 && let Some(mapped) = mappings.resolve_type(module_name, spec_name)
1438 {
1439 mapped.to_string()
1440 } else {
1441 to_pascal_case(spec_name)
1442 };
1443 return Some(format!("{}{}", crate_path, rust_type_name));
1444 }
1445 }
1446 None
1447 }
1448
1449 fn to_rust_variant_name(&self, name: &str) -> String {
1450 if name.is_empty() {
1451 return "Empty".to_string();
1452 }
1453 if let Some(mappings) = &self.config.name_mappings
1454 && let Some(mapped) = mappings.resolve_variant(&self.config.module_name, name)
1455 {
1456 return mapped.to_string();
1457 }
1458 let name = to_pascal_case(name);
1459 if name.chars().next().is_some_and(|c| c.is_ascii_digit()) {
1460 format!("_{}", name)
1461 } else {
1462 name
1463 }
1464 }
1465
1466 fn qname_to_field_name(&self, qname: &QName) -> String {
1467 if let Some(mappings) = &self.config.name_mappings
1468 && let Some(mapped) = mappings.resolve_field(&self.config.module_name, &qname.local)
1469 {
1470 return mapped.to_string();
1471 }
1472 to_snake_case(&qname.local)
1473 }
1474
1475 fn get_field_feature(&self, struct_name: &str, xml_field_name: &str) -> Option<String> {
1478 self.config
1479 .feature_mappings
1480 .as_ref()
1481 .and_then(|fm| {
1482 fm.primary_feature(&self.config.module_name, struct_name, xml_field_name)
1483 })
1484 .map(|feature| format!("{}-{}", self.config.module_name, feature))
1485 }
1486
1487 fn is_element_wrapper_type_alias(&self, name: &str) -> bool {
1490 if let Some(def_pattern) = self.definitions.get(name) {
1491 matches!(def_pattern, Pattern::Element { pattern, .. } if matches!(pattern.as_ref(), Pattern::Ref(_)))
1492 } else {
1493 false
1494 }
1495 }
1496
1497 fn pattern_to_rust_type(&self, pattern: &Pattern, is_vec: bool) -> (String, bool) {
1500 match pattern {
1501 Pattern::Ref(name) => {
1502 if self.definitions.contains_key(name.as_str()) {
1503 let type_name = self.to_rust_type_name(name);
1504 let is_complex = name.contains("_CT_") || name.contains("_EG_");
1507 let is_already_boxed = self.is_element_wrapper_type_alias(name);
1508 let needs_box = is_complex && !is_vec && !is_already_boxed;
1509 (type_name, needs_box)
1510 } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1511 let is_complex = name.contains("_CT_") || name.contains("_EG_");
1513 let needs_box = is_complex && !is_vec;
1514 (cross_crate, needs_box)
1515 } else {
1516 ("String".to_string(), false)
1517 }
1518 }
1519 Pattern::Datatype { library, name, .. } => {
1520 (xsd_to_rust(library, name).to_string(), false)
1521 }
1522 Pattern::Empty => ("()".to_string(), false),
1523 Pattern::StringLiteral(_) => ("String".to_string(), false),
1524 Pattern::Choice(_) => ("String".to_string(), false),
1525 _ => ("String".to_string(), false),
1526 }
1527 }
1528
1529 fn gen_element_parse_code(&self, field: &Field, is_empty_element: bool) -> String {
1532 let (rust_type, needs_box) = self.pattern_to_rust_type(&field.pattern, field.is_vec);
1534 let strategy = self.get_parse_strategy(&field.pattern);
1535
1536 let parse_expr = match strategy {
1537 ParseStrategy::FromXml => {
1538 let (actual_type, type_alias_has_box) =
1541 self.resolve_from_xml_type_with_box(&field.pattern);
1542 let final_type = actual_type.unwrap_or(rust_type.clone());
1543
1544 let mut expr = format!(
1545 "{}::from_xml(reader, &e, {})?",
1546 final_type, is_empty_element
1547 );
1548
1549 if type_alias_has_box {
1551 expr = format!("Box::new({})", expr);
1552 }
1553
1554 if needs_box {
1556 expr = format!("Box::new({})", expr);
1557 }
1558
1559 return expr;
1560 }
1561 ParseStrategy::TextFromStr => {
1562 if is_empty_element {
1563 "Default::default()".to_string()
1565 } else {
1566 "{ let text = read_text_content(reader)?; text.parse().map_err(|_| ParseError::InvalidValue(text))? }".to_string()
1567 }
1568 }
1569 ParseStrategy::TextString => {
1570 if is_empty_element {
1571 "String::new()".to_string()
1572 } else {
1573 "read_text_content(reader)?".to_string()
1574 }
1575 }
1576 ParseStrategy::TextHexBinary => {
1577 if is_empty_element {
1578 "Vec::new()".to_string()
1579 } else {
1580 "{ let text = read_text_content(reader)?; decode_hex(&text).unwrap_or_default() }".to_string()
1581 }
1582 }
1583 ParseStrategy::TextBase64Binary => {
1584 if is_empty_element {
1585 "Vec::new()".to_string()
1586 } else {
1587 "{ let text = read_text_content(reader)?; decode_base64(&text).unwrap_or_default() }".to_string()
1588 }
1589 }
1590 };
1591
1592 if strategy != ParseStrategy::FromXml && needs_box {
1594 format!("Box::new({})", parse_expr)
1595 } else {
1596 parse_expr
1597 }
1598 }
1599
1600 fn resolve_from_xml_type_with_box(&self, pattern: &Pattern) -> (Option<String>, bool) {
1605 match pattern {
1606 Pattern::Ref(name) => {
1607 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1609 if self.is_inline_attribute_ref(name, def_pattern) {
1611 return (None, false);
1612 }
1613 if let Pattern::Element { pattern: inner, .. } = def_pattern
1617 && let Some(inner_type) = self.resolve_from_xml_type_simple(inner)
1618 {
1619 let type_alias_has_box = if let Pattern::Ref(inner_name) = inner.as_ref() {
1621 inner_name.contains("_CT_") || inner_name.contains("_EG_")
1622 } else {
1623 false
1624 };
1625 return (Some(inner_type), type_alias_has_box);
1626 }
1627 if name.contains("_CT_") {
1631 return (Some(self.to_rust_type_name(name)), false);
1632 }
1633 if let Pattern::Ref(inner_name) = def_pattern
1636 && !self.definitions.contains_key(inner_name.as_str())
1637 {
1638 if let Some(cross_crate) = self.resolve_cross_crate_type(inner_name) {
1640 return (Some(cross_crate), false);
1641 }
1642 return (None, false);
1644 } else if let Pattern::Ref(inner_name) = def_pattern {
1645 return self
1646 .resolve_from_xml_type_with_box(&Pattern::Ref(inner_name.clone()));
1647 }
1648 } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1649 return (Some(cross_crate), false);
1651 }
1652 (Some(self.to_rust_type_name(name)), false)
1654 }
1655 _ => (None, false),
1656 }
1657 }
1658
1659 fn resolve_from_xml_type_simple(&self, pattern: &Pattern) -> Option<String> {
1661 match pattern {
1662 Pattern::Ref(name) => {
1663 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1664 if let Pattern::Element { pattern: inner, .. } = def_pattern {
1665 return self.resolve_from_xml_type_simple(inner);
1666 }
1667 if let Pattern::Ref(inner_name) = def_pattern {
1668 if !self.definitions.contains_key(inner_name.as_str()) {
1670 if let Some(cross_crate) = self.resolve_cross_crate_type(inner_name) {
1672 return Some(cross_crate);
1673 }
1674 return None;
1676 }
1677 return self
1678 .resolve_from_xml_type_simple(&Pattern::Ref(inner_name.clone()));
1679 }
1680 } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1681 return Some(cross_crate);
1683 }
1684 Some(self.to_rust_type_name(name))
1685 }
1686 _ => None,
1687 }
1688 }
1689
1690 fn get_parse_strategy(&self, pattern: &Pattern) -> ParseStrategy {
1692 match pattern {
1693 Pattern::Ref(name) => {
1694 if name.contains("_CT_") || name.contains("_EG_") {
1696 return ParseStrategy::FromXml;
1697 }
1698
1699 if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1701 if let Pattern::Ref(inner_name) = def_pattern
1704 && !self.definitions.contains_key(inner_name.as_str())
1705 {
1706 if inner_name.contains("_CT_") || inner_name.contains("_EG_") {
1708 return ParseStrategy::FromXml;
1709 }
1710 return ParseStrategy::FromXml;
1713 }
1714 return self.get_parse_strategy(def_pattern);
1715 } else if self.resolve_cross_crate_type(name).is_some() {
1716 return ParseStrategy::FromXml;
1718 }
1719
1720 ParseStrategy::TextString
1722 }
1723 Pattern::Datatype { library, name, .. } => {
1724 if library == "xsd" {
1725 match name.as_str() {
1726 "string" | "token" | "NCName" | "ID" | "IDREF" | "anyURI" | "dateTime"
1727 | "date" | "time" => ParseStrategy::TextString,
1728 "hexBinary" => ParseStrategy::TextHexBinary,
1729 "base64Binary" => ParseStrategy::TextBase64Binary,
1730 _ => ParseStrategy::TextFromStr,
1732 }
1733 } else {
1734 ParseStrategy::TextString
1735 }
1736 }
1737 Pattern::Choice(variants)
1739 if variants
1740 .iter()
1741 .all(|v| matches!(v, Pattern::StringLiteral(_))) =>
1742 {
1743 ParseStrategy::TextFromStr
1744 }
1745 Pattern::StringLiteral(_) => ParseStrategy::TextString,
1746 Pattern::Empty => ParseStrategy::TextString,
1747 Pattern::List(_) => ParseStrategy::TextString,
1748 _ => ParseStrategy::FromXml,
1750 }
1751 }
1752}
1753
1754pub(crate) struct Field {
1755 pub name: String,
1756 pub xml_name: String,
1757 pub xml_prefix: Option<String>,
1758 pub pattern: Pattern,
1759 pub is_optional: bool,
1760 pub is_attribute: bool,
1761 pub is_vec: bool,
1762 pub is_text_content: bool,
1763}
1764
1765pub(crate) fn strip_namespace_prefix(name: &str) -> &str {
1766 for kind in ["CT_", "ST_", "EG_"] {
1767 if let Some(pos) = name.find(kind)
1768 && pos > 0
1769 {
1770 return &name[pos..];
1771 }
1772 }
1773 name
1774}
1775
1776pub(crate) fn to_pascal_case(s: &str) -> String {
1777 let mut result = String::new();
1778 let mut capitalize_next = true;
1779 for ch in s.chars() {
1780 if ch == '_' || ch == '-' {
1781 capitalize_next = true;
1782 } else if capitalize_next {
1783 result.extend(ch.to_uppercase());
1784 capitalize_next = false;
1785 } else {
1786 result.push(ch);
1787 }
1788 }
1789 result
1790}
1791
1792pub(crate) fn to_snake_case(s: &str) -> String {
1793 let mut result = String::new();
1794 for (i, ch) in s.chars().enumerate() {
1795 if ch.is_uppercase() && i > 0 {
1796 result.push('_');
1797 }
1798 result.extend(ch.to_lowercase());
1799 }
1800 match result.as_str() {
1801 "type" => "r#type".to_string(),
1803 "ref" => "r#ref".to_string(),
1804 "match" => "r#match".to_string(),
1805 "in" => "r#in".to_string(),
1806 "for" => "r#for".to_string(),
1807 "macro" => "r#macro".to_string(),
1808 "if" => "r#if".to_string(),
1809 "else" => "r#else".to_string(),
1810 "loop" => "r#loop".to_string(),
1811 "break" => "r#break".to_string(),
1812 "continue" => "r#continue".to_string(),
1813 "return" => "r#return".to_string(),
1814 "self" => "r#self".to_string(),
1815 "super" => "r#super".to_string(),
1816 "crate" => "r#crate".to_string(),
1817 "mod" => "r#mod".to_string(),
1818 "pub" => "r#pub".to_string(),
1819 "use" => "r#use".to_string(),
1820 "as" => "r#as".to_string(),
1821 "static" => "r#static".to_string(),
1822 "const" => "r#const".to_string(),
1823 "extern" => "r#extern".to_string(),
1824 "fn" => "r#fn".to_string(),
1825 "struct" => "r#struct".to_string(),
1826 "enum" => "r#enum".to_string(),
1827 "trait" => "r#trait".to_string(),
1828 "impl" => "r#impl".to_string(),
1829 "where" => "r#where".to_string(),
1830 "async" => "r#async".to_string(),
1831 "await" => "r#await".to_string(),
1832 "move" => "r#move".to_string(),
1833 "box" => "r#box".to_string(),
1834 "dyn" => "r#dyn".to_string(),
1835 "abstract" => "r#abstract".to_string(),
1836 "become" => "r#become".to_string(),
1837 "do" => "r#do".to_string(),
1838 "final" => "r#final".to_string(),
1839 "override" => "r#override".to_string(),
1840 "priv" => "r#priv".to_string(),
1841 "typeof" => "r#typeof".to_string(),
1842 "unsized" => "r#unsized".to_string(),
1843 "virtual" => "r#virtual".to_string(),
1844 "yield" => "r#yield".to_string(),
1845 "try" => "r#try".to_string(),
1846 _ => result,
1847 }
1848}
1849
1850pub(crate) fn xsd_to_rust(library: &str, name: &str) -> &'static str {
1851 if library == "xsd" {
1852 match name {
1853 "string" => "String",
1854 "integer" => "i64",
1855 "int" => "i32",
1856 "long" => "i64",
1857 "short" => "i16",
1858 "byte" => "i8",
1859 "unsignedInt" => "u32",
1860 "unsignedLong" => "u64",
1861 "unsignedShort" => "u16",
1862 "unsignedByte" => "u8",
1863 "boolean" => "bool",
1864 "double" => "f64",
1865 "float" => "f32",
1866 "decimal" => "f64",
1867 "hexBinary" | "base64Binary" => "Vec<u8>",
1868 _ => "String",
1869 }
1870 } else {
1871 "String"
1872 }
1873}