Skip to main content

ooxml_codegen/
parser_gen.rs

1//! Event-based XML parser generator.
2//!
3//! This module generates quick-xml event-based parsers for OOXML types,
4//! which are ~3x faster than serde-based deserialization.
5
6use crate::ast::{Pattern, QName, Schema};
7use crate::codegen::CodegenConfig;
8use std::collections::{HashMap, HashSet};
9use std::fmt::Write;
10
11/// Generate parser code for all types in the schema.
12pub fn generate_parsers(schema: &Schema, config: &CodegenConfig) -> String {
13    let mut g = ParserGenerator::new(schema, config);
14    g.run()
15}
16
17/// How to parse a field value from XML.
18#[derive(Debug, Clone, Copy, PartialEq)]
19enum ParseStrategy {
20    /// Call from_xml on a complex type (CT_* or EG_*)
21    FromXml,
22    /// Read text content and use FromStr (enums, numbers)
23    TextFromStr,
24    /// Read text content as String directly
25    TextString,
26    /// Read text content and decode as hex (Vec<u8>)
27    TextHexBinary,
28    /// Read text content and decode as base64 (Vec<u8>)
29    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    /// Track generated Rust type names to avoid duplicate impl blocks from merged schemas.
38    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        // Generate parsers for complex types only
62        for def in &self.schema.definitions {
63            if !def.name.contains("_ST_") && !self.is_simple_type(&def.pattern) {
64                // Skip inline attribute references (like r_id) - they're inlined into parent types
65                if self.is_inline_attribute_ref(&def.name, &def.pattern) {
66                    continue;
67                }
68                // Deduplicate by Rust type name to avoid duplicate impl blocks from merged schemas.
69                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                    // Element group - generate enum parser
75                    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                    // Complex type struct - generate struct parser (skip type aliases)
81                    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    /// Check if a pattern would generate a type alias rather than a struct.
93    /// Type aliases are generated for:
94    /// - Pattern::Element { pattern } (element-only definitions)
95    /// - Pattern::Datatype (XSD type alias)
96    /// - Pattern::Ref to a simple type, datatype, or unknown definition
97    ///
98    /// We DON'T skip Ref patterns that point to attribute definitions,
99    /// because those generate structs that need FromXml impls.
100    fn is_type_alias(&self, pattern: &Pattern) -> bool {
101        match pattern {
102            // Element wrappers are always type aliases
103            Pattern::Element { .. } => true,
104            // Direct datatype references are type aliases
105            Pattern::Datatype { .. } => true,
106            // Refs need to be checked - only skip if they resolve to simple types
107            Pattern::Ref(name) => {
108                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
109                    // If it resolves to a simple type (choice of strings, datatype, etc.)
110                    self.is_simple_type(def_pattern)
111                        // Or to another type alias
112                        || self.is_type_alias(def_pattern)
113                } else {
114                    // Unknown ref (from another schema) - these generate empty structs
115                    // that still need FromXml impls
116                    false
117                }
118            }
119            _ => false,
120        }
121    }
122
123    /// Check if a definition is a pure attribute reference that should be inlined.
124    /// These are attribute patterns (like r_id, r_embed) that don't have CT_ in their name.
125    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        // Add cross-crate imports for types from other schemas
145        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        // Import shared traits and error types from ooxml-xml
152        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        // Add skip_element helper (allow dead_code since extra-children feature captures instead)
161        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        // Add read_text_content helper for reading element text
190        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        // Entity references (&amp; &lt; etc.) arrive as GeneralRef events when
216        // expand_empty_elements is false or the reader is in non-expanding mode.
217        writeln!(self.output, "            Event::GeneralRef(e) => {{").unwrap();
218        writeln!(
219            self.output,
220            "                let name = e.decode().unwrap_or_default();"
221        )
222        .unwrap();
223        writeln!(
224            self.output,
225            "                if let Some(s) = quick_xml::escape::resolve_xml_entity(&name) {{"
226        )
227        .unwrap();
228        writeln!(self.output, "                    text.push_str(s);").unwrap();
229        writeln!(self.output, "                }}").unwrap();
230        writeln!(self.output, "            }},").unwrap();
231        writeln!(self.output, "            Event::End(_) => break,").unwrap();
232        writeln!(self.output, "            Event::Eof => break,").unwrap();
233        writeln!(self.output, "            _ => {{}}").unwrap();
234        writeln!(self.output, "        }}").unwrap();
235        writeln!(self.output, "        buf.clear();").unwrap();
236        writeln!(self.output, "    }}").unwrap();
237        writeln!(self.output, "    Ok(text)").unwrap();
238        writeln!(self.output, "}}").unwrap();
239        writeln!(self.output).unwrap();
240        // Add decode_hex helper for hexBinary types
241        writeln!(self.output, "#[allow(dead_code)]").unwrap();
242        writeln!(self.output, "/// Decode a hex string to bytes.").unwrap();
243        writeln!(self.output, "fn decode_hex(s: &str) -> Option<Vec<u8>> {{").unwrap();
244        writeln!(self.output, "    let s = s.trim();").unwrap();
245        writeln!(self.output, "    if s.len() % 2 != 0 {{ return None; }}").unwrap();
246        writeln!(self.output, "    (0..s.len())").unwrap();
247        writeln!(self.output, "        .step_by(2)").unwrap();
248        writeln!(
249            self.output,
250            "        .map(|i| u8::from_str_radix(&s[i..i + 2], 16).ok())"
251        )
252        .unwrap();
253        writeln!(self.output, "        .collect()").unwrap();
254        writeln!(self.output, "}}").unwrap();
255        writeln!(self.output).unwrap();
256
257        // Add decode_base64 helper for base64Binary types
258        writeln!(self.output, "#[allow(dead_code)]").unwrap();
259        writeln!(self.output, "/// Decode a base64 string to bytes.").unwrap();
260        writeln!(
261            self.output,
262            "fn decode_base64(s: &str) -> Option<Vec<u8>> {{"
263        )
264        .unwrap();
265        writeln!(self.output, "    use base64::Engine;").unwrap();
266        writeln!(
267            self.output,
268            "    base64::engine::general_purpose::STANDARD.decode(s.trim()).ok()"
269        )
270        .unwrap();
271        writeln!(self.output, "}}").unwrap();
272        writeln!(self.output).unwrap();
273    }
274
275    fn is_simple_type(&self, pattern: &Pattern) -> bool {
276        match pattern {
277            Pattern::Choice(variants) => variants
278                .iter()
279                .all(|v| matches!(v, Pattern::StringLiteral(_))),
280            Pattern::StringLiteral(_) => true,
281            Pattern::Datatype { .. } => true,
282            Pattern::List(_) => true,
283            Pattern::Ref(name) => self
284                .definitions
285                .get(name.as_str())
286                .is_some_and(|p| self.is_simple_type(p)),
287            _ => false,
288        }
289    }
290
291    fn is_element_choice(&self, pattern: &Pattern) -> bool {
292        match pattern {
293            Pattern::Choice(variants) => variants.iter().any(Self::is_direct_element_variant),
294            _ => false,
295        }
296    }
297
298    fn is_direct_element_variant(pattern: &Pattern) -> bool {
299        match pattern {
300            Pattern::Element { .. } => true,
301            Pattern::Optional(inner) | Pattern::ZeroOrMore(inner) | Pattern::OneOrMore(inner) => {
302                Self::is_direct_element_variant(inner)
303            }
304            _ => false,
305        }
306    }
307
308    /// Check if a pattern contains XML child elements (even from unresolved refs).
309    fn has_xml_children_pattern(&self, pattern: &Pattern) -> bool {
310        match pattern {
311            Pattern::Empty => false,
312            Pattern::Attribute { .. } => false,
313            Pattern::Element { .. } => true,
314            Pattern::Ref(name) => {
315                if name.contains("_AG_") {
316                    return false;
317                }
318                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
319                    self.has_xml_children_pattern(def_pattern)
320                } else {
321                    true
322                }
323            }
324            Pattern::Sequence(items) | Pattern::Interleave(items) | Pattern::Choice(items) => {
325                items.iter().any(|i| self.has_xml_children_pattern(i))
326            }
327            Pattern::Optional(inner)
328            | Pattern::ZeroOrMore(inner)
329            | Pattern::OneOrMore(inner)
330            | Pattern::Group(inner)
331            | Pattern::Mixed(inner) => self.has_xml_children_pattern(inner),
332            Pattern::Text => true,
333            _ => false,
334        }
335    }
336
337    /// Check if a pattern contains XML attributes (even from unresolved refs).
338    fn has_xml_attr_pattern(&self, pattern: &Pattern) -> bool {
339        match pattern {
340            Pattern::Attribute { .. } => true,
341            Pattern::Ref(name) if name.contains("_AG_") => true,
342            Pattern::Ref(name) => {
343                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
344                    self.has_xml_attr_pattern(def_pattern)
345                } else {
346                    false
347                }
348            }
349            Pattern::Sequence(items) | Pattern::Interleave(items) | Pattern::Choice(items) => {
350                items.iter().any(|i| self.has_xml_attr_pattern(i))
351            }
352            Pattern::Optional(inner)
353            | Pattern::ZeroOrMore(inner)
354            | Pattern::OneOrMore(inner)
355            | Pattern::Group(inner) => self.has_xml_attr_pattern(inner),
356            _ => false,
357        }
358    }
359
360    fn eg_ref_to_field_name(&self, name: &str) -> String {
361        let spec_name = strip_namespace_prefix(name);
362        let short = spec_name.strip_prefix("EG_").unwrap_or(spec_name);
363        // Check names.yaml field mapping first
364        if let Some(mappings) = &self.config.name_mappings
365            && let Some(mapped) = mappings.resolve_field(&self.config.module_name, short)
366        {
367            return mapped.to_string();
368        }
369        to_snake_case(short)
370    }
371
372    fn is_eg_content_field(&self, field: &Field) -> bool {
373        if let Pattern::Ref(name) = &field.pattern
374            && name.contains("_EG_")
375            && let Some(pattern) = self.definitions.get(name.as_str())
376        {
377            return self.is_element_choice(pattern);
378        }
379        false
380    }
381
382    /// Recursively collect all element XML local names from an EG_* definition.
383    fn collect_element_variant_names(
384        &self,
385        pattern: &Pattern,
386        names: &mut Vec<String>,
387        visited: &mut std::collections::HashSet<String>,
388    ) {
389        match pattern {
390            Pattern::Element { name, .. } => {
391                names.push(name.local.clone());
392            }
393            Pattern::Optional(inner)
394            | Pattern::ZeroOrMore(inner)
395            | Pattern::OneOrMore(inner)
396            | Pattern::Group(inner) => {
397                self.collect_element_variant_names(inner, names, visited);
398            }
399            Pattern::Ref(name) if name.contains("_EG_") && visited.insert(name.clone()) => {
400                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
401                    self.collect_element_variant_names(def_pattern, names, visited);
402                }
403            }
404            Pattern::Choice(items) | Pattern::Sequence(items) | Pattern::Interleave(items) => {
405                for item in items {
406                    self.collect_element_variant_names(item, names, visited);
407                }
408            }
409            _ => {}
410        }
411    }
412
413    /// Recursively collect element variants with their types for EG enum parsers.
414    /// Returns tuples of (xml_name, parse_type, needs_box, type_alias_has_box).
415    fn collect_eg_variants(
416        &self,
417        pattern: &Pattern,
418        variants: &mut Vec<(String, String, bool, bool)>,
419        visited: &mut std::collections::HashSet<String>,
420    ) {
421        match pattern {
422            Pattern::Element { name, pattern } => {
423                // Enum variants are not in Vec context, so may need boxing
424                let (rust_type, needs_box) = self.pattern_to_rust_type(pattern, false);
425                // For type aliases (Pattern::Element wrappers), resolve to the inner type
426                // that actually has a FromXml impl
427                let (actual_type, type_alias_has_box) =
428                    self.resolve_from_xml_type_with_box(pattern);
429                let inner_type = actual_type.unwrap_or(rust_type);
430                variants.push((
431                    name.local.clone(),
432                    inner_type,
433                    needs_box,
434                    type_alias_has_box,
435                ));
436            }
437            Pattern::Optional(inner)
438            | Pattern::ZeroOrMore(inner)
439            | Pattern::OneOrMore(inner)
440            | Pattern::Group(inner) => {
441                self.collect_eg_variants(inner, variants, visited);
442            }
443            Pattern::Ref(name) if name.contains("_EG_") && visited.insert(name.clone()) => {
444                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
445                    self.collect_eg_variants(def_pattern, variants, visited);
446                }
447            }
448            Pattern::Choice(items) | Pattern::Sequence(items) | Pattern::Interleave(items) => {
449                for item in items {
450                    self.collect_eg_variants(item, variants, visited);
451                }
452            }
453            _ => {}
454        }
455    }
456
457    fn gen_element_group_parser(&self, def: &crate::ast::Definition) -> Option<String> {
458        let rust_name = self.to_rust_type_name(&def.name);
459
460        let Pattern::Choice(variants) = &def.pattern else {
461            return None;
462        };
463
464        // Collect element variants recursively (follows nested EG_* refs)
465        let mut element_variants = Vec::new();
466        let mut visited = std::collections::HashSet::new();
467        visited.insert(def.name.clone());
468        for v in variants {
469            self.collect_eg_variants(v, &mut element_variants, &mut visited);
470        }
471        // Dedup by xml name
472        let mut seen = std::collections::HashSet::new();
473        element_variants.retain(|(name, _, _, _)| seen.insert(name.clone()));
474
475        if element_variants.is_empty() {
476            return None;
477        }
478
479        let mut code = String::new();
480        writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
481        writeln!(
482            code,
483            "    fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
484        )
485        .unwrap();
486        writeln!(code, "        let tag = start_tag.local_name();").unwrap();
487        writeln!(code, "        match tag.as_ref() {{").unwrap();
488
489        for (xml_name, inner_type, needs_box, type_alias_has_box) in &element_variants {
490            let variant_name = self.to_rust_variant_name(xml_name);
491            writeln!(code, "            b\"{}\" => {{", xml_name).unwrap();
492            writeln!(
493                code,
494                "                let inner = {}::from_xml(reader, start_tag, is_empty)?;",
495                inner_type
496            )
497            .unwrap();
498            // When the type alias already has Box (e.g., CTFoo = Box<Inner>),
499            // we need to wrap inner once for the alias, then again for the enum variant.
500            // When no type alias box, we just need one Box for the enum variant.
501            let wrap_expr = match (*needs_box, *type_alias_has_box) {
502                (true, true) => "Box::new(Box::new(inner))",
503                (true, false) => "Box::new(inner)",
504                (false, true) => "Box::new(inner)",
505                (false, false) => "inner",
506            };
507            writeln!(
508                code,
509                "                Ok(Self::{}({}))",
510                variant_name, wrap_expr
511            )
512            .unwrap();
513            writeln!(code, "            }}").unwrap();
514        }
515
516        writeln!(code, "            _ => Err(ParseError::UnexpectedElement(").unwrap();
517        writeln!(
518            code,
519            "                String::from_utf8_lossy(start_tag.name().as_ref()).into_owned()"
520        )
521        .unwrap();
522        writeln!(code, "            )),").unwrap();
523        writeln!(code, "        }}").unwrap();
524        writeln!(code, "    }}").unwrap();
525        writeln!(code, "}}").unwrap();
526
527        Some(code)
528    }
529
530    fn gen_struct_parser(&self, def: &crate::ast::Definition) -> Option<String> {
531        let rust_name = self.to_rust_type_name(&def.name);
532        let fields = self.extract_fields(&def.pattern);
533
534        if fields.is_empty() {
535            let has_unresolved_children = self.has_xml_children_pattern(&def.pattern);
536            let has_unresolved_attrs = self.has_xml_attr_pattern(&def.pattern);
537
538            let mut code = String::new();
539            writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
540
541            if has_unresolved_children || has_unresolved_attrs {
542                // Struct with extra_children/extra_attrs — capture unknown XML
543                writeln!(
544                    code,
545                    "    fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
546                )
547                .unwrap();
548                if has_unresolved_attrs {
549                    writeln!(code, "        #[cfg(feature = \"extra-attrs\")]").unwrap();
550                    writeln!(
551                        code,
552                        "        let mut extra_attrs = std::collections::HashMap::new();"
553                    )
554                    .unwrap();
555                    writeln!(code, "        #[cfg(feature = \"extra-attrs\")]").unwrap();
556                    writeln!(
557                        code,
558                        "        for attr in start_tag.attributes().filter_map(|a| a.ok()) {{"
559                    )
560                    .unwrap();
561                    writeln!(
562                        code,
563                        "            let key = String::from_utf8_lossy(attr.key.as_ref()).into_owned();"
564                    )
565                    .unwrap();
566                    writeln!(
567                        code,
568                        "            let val = String::from_utf8_lossy(&attr.value).into_owned();"
569                    )
570                    .unwrap();
571                    writeln!(code, "            extra_attrs.insert(key, val);").unwrap();
572                    writeln!(code, "        }}").unwrap();
573                }
574                if has_unresolved_children {
575                    writeln!(code, "        #[cfg(feature = \"extra-children\")]").unwrap();
576                    writeln!(code, "        let mut extra_children = Vec::new();").unwrap();
577                    writeln!(code, "        #[cfg(feature = \"extra-children\")]").unwrap();
578                    writeln!(code, "        let mut child_idx: usize = 0;").unwrap();
579                }
580                writeln!(code, "        if !is_empty {{").unwrap();
581                writeln!(code, "            let mut buf = Vec::new();").unwrap();
582                writeln!(code, "            loop {{").unwrap();
583                writeln!(
584                    code,
585                    "                match reader.read_event_into(&mut buf)? {{"
586                )
587                .unwrap();
588                if has_unresolved_children {
589                    writeln!(
590                        code,
591                        "                    #[cfg(feature = \"extra-children\")]"
592                    )
593                    .unwrap();
594                    writeln!(code, "                    Event::Start(e) => {{").unwrap();
595                    writeln!(
596                        code,
597                        "                        let elem = RawXmlElement::from_reader(reader, &e)?;"
598                    )
599                    .unwrap();
600                    writeln!(
601                        code,
602                        "                        extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
603                    )
604                    .unwrap();
605                    writeln!(code, "                        child_idx += 1;").unwrap();
606                    writeln!(code, "                    }}").unwrap();
607                    writeln!(
608                        code,
609                        "                    #[cfg(not(feature = \"extra-children\"))]"
610                    )
611                    .unwrap();
612                    writeln!(
613                        code,
614                        "                    Event::Start(_) => {{ skip_element(reader)?; }}"
615                    )
616                    .unwrap();
617                    writeln!(
618                        code,
619                        "                    #[cfg(feature = \"extra-children\")]"
620                    )
621                    .unwrap();
622                    writeln!(code, "                    Event::Empty(e) => {{").unwrap();
623                    writeln!(
624                        code,
625                        "                        let elem = RawXmlElement::from_empty(&e);"
626                    )
627                    .unwrap();
628                    writeln!(
629                        code,
630                        "                        extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
631                    )
632                    .unwrap();
633                    writeln!(code, "                        child_idx += 1;").unwrap();
634                    writeln!(code, "                    }}").unwrap();
635                    writeln!(
636                        code,
637                        "                    #[cfg(not(feature = \"extra-children\"))]"
638                    )
639                    .unwrap();
640                    writeln!(code, "                    Event::Empty(_) => {{}}").unwrap();
641                } else {
642                    writeln!(
643                        code,
644                        "                    Event::Start(_) => {{ skip_element(reader)?; }}"
645                    )
646                    .unwrap();
647                    writeln!(code, "                    Event::Empty(_) => {{}}").unwrap();
648                }
649                writeln!(code, "                    Event::End(_) => break,").unwrap();
650                writeln!(code, "                    Event::Eof => break,").unwrap();
651                writeln!(code, "                    _ => {{}}").unwrap();
652                writeln!(code, "                }}").unwrap();
653                writeln!(code, "                buf.clear();").unwrap();
654                writeln!(code, "            }}").unwrap();
655                writeln!(code, "        }}").unwrap();
656                writeln!(code, "        Ok(Self {{").unwrap();
657                if has_unresolved_attrs {
658                    writeln!(code, "            #[cfg(feature = \"extra-attrs\")]").unwrap();
659                    writeln!(code, "            extra_attrs,").unwrap();
660                }
661                if has_unresolved_children {
662                    writeln!(code, "            #[cfg(feature = \"extra-children\")]").unwrap();
663                    writeln!(code, "            extra_children,").unwrap();
664                }
665                writeln!(code, "        }})").unwrap();
666            } else {
667                // Truly empty struct - skip all children with depth tracking
668                writeln!(
669                    code,
670                    "    fn from_xml<R: BufRead>(reader: &mut Reader<R>, _start: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
671                )
672                .unwrap();
673                writeln!(code, "        if !is_empty {{").unwrap();
674                writeln!(code, "            let mut buf = Vec::new();").unwrap();
675                writeln!(code, "            let mut depth = 1u32;").unwrap();
676                writeln!(code, "            loop {{").unwrap();
677                writeln!(
678                    code,
679                    "                match reader.read_event_into(&mut buf)? {{"
680                )
681                .unwrap();
682                writeln!(code, "                    Event::Start(_) => depth += 1,").unwrap();
683                writeln!(
684                    code,
685                    "                    Event::End(_) => {{ depth -= 1; if depth == 0 {{ break; }} }}"
686                )
687                .unwrap();
688                writeln!(code, "                    Event::Eof => break,").unwrap();
689                writeln!(code, "                    _ => {{}}").unwrap();
690                writeln!(code, "                }}").unwrap();
691                writeln!(code, "                buf.clear();").unwrap();
692                writeln!(code, "            }}").unwrap();
693                writeln!(code, "        }}").unwrap();
694                writeln!(code, "        Ok(Self {{}})").unwrap();
695            }
696
697            writeln!(code, "    }}").unwrap();
698            writeln!(code, "}}").unwrap();
699            return Some(code);
700        }
701
702        let mut code = String::new();
703        writeln!(code, "impl FromXml for {} {{", rust_name).unwrap();
704        writeln!(
705            code,
706            "    fn from_xml<R: BufRead>(reader: &mut Reader<R>, start_tag: &BytesStart, is_empty: bool) -> Result<Self, ParseError> {{"
707        )
708        .unwrap();
709
710        // Declare field variables with f_ prefix to avoid shadowing function parameters
711        for field in &fields {
712            // Strip r# from raw identifiers and leading underscores before prefixing
713            let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
714            let base_name = base_name.trim_start_matches('_');
715            let var_name = format!("f_{}", base_name);
716
717            // Add cfg attribute for feature-gated fields
718            if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
719                write!(code, "        #[cfg(feature = \"{}\")] ", feature).unwrap();
720            } else {
721                write!(code, "        ").unwrap();
722            }
723
724            if field.is_vec {
725                writeln!(code, "let mut {} = Vec::new();", var_name).unwrap();
726            } else if field.is_optional {
727                writeln!(code, "let mut {} = None;", var_name).unwrap();
728            } else {
729                // Required non-Vec field - may need boxing for recursive types
730                let (rust_type, needs_box) = self.pattern_to_rust_type(&field.pattern, false);
731                let full_type = if needs_box {
732                    format!("Box<{}>", rust_type)
733                } else {
734                    rust_type
735                };
736                writeln!(code, "let mut {}: Option<{}> = None;", var_name, full_type).unwrap();
737            }
738        }
739
740        // Parse attributes
741        let attr_fields: Vec<_> = fields.iter().filter(|f| f.is_attribute).collect();
742        let has_attrs = !attr_fields.is_empty();
743        let elem_fields: Vec<_> = fields
744            .iter()
745            .filter(|f| !f.is_attribute && !f.is_text_content)
746            .collect();
747        let text_fields: Vec<_> = fields.iter().filter(|f| f.is_text_content).collect();
748        let has_children = !elem_fields.is_empty();
749        let has_parsing_loop = has_children || !text_fields.is_empty();
750        if has_attrs {
751            // Declare extra_attrs for capturing unknown attributes (feature-gated)
752            writeln!(code, "        #[cfg(feature = \"extra-attrs\")]").unwrap();
753            writeln!(
754                code,
755                "        let mut extra_attrs = std::collections::HashMap::new();"
756            )
757            .unwrap();
758        }
759        if has_parsing_loop {
760            // Declare extra_children for capturing unknown child elements (feature-gated)
761            writeln!(code, "        #[cfg(feature = \"extra-children\")]").unwrap();
762            writeln!(code, "        let mut extra_children = Vec::new();").unwrap();
763            writeln!(code, "        #[cfg(feature = \"extra-children\")]").unwrap();
764            writeln!(code, "        let mut child_idx: usize = 0;").unwrap();
765        }
766        if has_attrs || has_parsing_loop {
767            writeln!(code).unwrap();
768        }
769        if has_attrs {
770            writeln!(code, "        // Parse attributes").unwrap();
771            writeln!(
772                code,
773                "        for attr in start_tag.attributes().filter_map(|a| a.ok()) {{"
774            )
775            .unwrap();
776            writeln!(
777                code,
778                "            let val = String::from_utf8_lossy(&attr.value);"
779            )
780            .unwrap();
781            writeln!(code, "            match attr.key.local_name().as_ref() {{").unwrap();
782            for field in &attr_fields {
783                let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
784                let base_name = base_name.trim_start_matches('_');
785                let var_name = format!("f_{}", base_name);
786                let parse_expr = self.gen_attr_parse_expr(&field.pattern);
787
788                // Add cfg attribute for feature-gated fields
789                if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
790                    writeln!(code, "                #[cfg(feature = \"{}\")]", feature).unwrap();
791                }
792                writeln!(code, "                b\"{}\" => {{", field.xml_name).unwrap();
793                writeln!(code, "                    {} = {};", var_name, parse_expr).unwrap();
794                writeln!(code, "                }}").unwrap();
795            }
796            // Capture unknown attributes for roundtrip fidelity (feature-gated)
797            writeln!(code, "                #[cfg(feature = \"extra-attrs\")]").unwrap();
798            writeln!(code, "                unknown => {{").unwrap();
799            writeln!(
800                code,
801                "                    let key = String::from_utf8_lossy(attr.key.as_ref()).into_owned();"
802            )
803            .unwrap();
804            writeln!(
805                code,
806                "                    extra_attrs.insert(key, val.into_owned());"
807            )
808            .unwrap();
809            writeln!(code, "                }}").unwrap();
810            writeln!(
811                code,
812                "                #[cfg(not(feature = \"extra-attrs\"))]"
813            )
814            .unwrap();
815            writeln!(code, "                _ => {{}}").unwrap();
816            writeln!(code, "            }}").unwrap();
817            writeln!(code, "        }}").unwrap();
818        }
819
820        // Parse child elements and text content (only if not empty element)
821        if has_parsing_loop {
822            writeln!(code).unwrap();
823            writeln!(code, "        // Parse child elements").unwrap();
824            writeln!(code, "        if !is_empty {{").unwrap();
825            writeln!(code, "            let mut buf = Vec::new();").unwrap();
826            writeln!(code, "            loop {{").unwrap();
827            writeln!(
828                code,
829                "                match reader.read_event_into(&mut buf)? {{"
830            )
831            .unwrap();
832            writeln!(code, "                    Event::Start(e) => {{").unwrap();
833            writeln!(
834                code,
835                "                        match e.local_name().as_ref() {{"
836            )
837            .unwrap();
838
839            // Track matched element names to avoid duplicate match arms
840            let mut matched_names = std::collections::HashSet::new();
841            for field in &elem_fields {
842                let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
843                let base_name = base_name.trim_start_matches('_');
844                let var_name = format!("f_{}", base_name);
845                let parse_expr = self.gen_element_parse_code(field, false);
846
847                // Add cfg attribute for feature-gated fields
848                if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
849                    writeln!(
850                        code,
851                        "                            #[cfg(feature = \"{}\")]",
852                        feature
853                    )
854                    .unwrap();
855                }
856                if self.is_eg_content_field(field) {
857                    // EG content field: match all variant element names (dedup across fields)
858                    let mut variant_names = Vec::new();
859                    let mut visited = std::collections::HashSet::new();
860                    if let Some(def_pattern) = self.definitions.get(field.xml_name.as_str()) {
861                        self.collect_element_variant_names(
862                            def_pattern,
863                            &mut variant_names,
864                            &mut visited,
865                        );
866                    }
867                    variant_names.retain(|n| matched_names.insert(n.clone()));
868                    if !variant_names.is_empty() {
869                        let arms: Vec<_> = variant_names
870                            .iter()
871                            .map(|n| format!("b\"{}\"", n))
872                            .collect();
873                        writeln!(
874                            code,
875                            "                            {} => {{",
876                            arms.join(" | ")
877                        )
878                        .unwrap();
879                    } else {
880                        // All variants already matched by earlier field — skip
881                        continue;
882                    }
883                } else {
884                    matched_names.insert(field.xml_name.clone());
885                    writeln!(
886                        code,
887                        "                            b\"{}\" => {{",
888                        field.xml_name
889                    )
890                    .unwrap();
891                }
892                if field.is_vec {
893                    writeln!(
894                        code,
895                        "                                {}.push({});",
896                        var_name, parse_expr
897                    )
898                    .unwrap();
899                } else {
900                    writeln!(
901                        code,
902                        "                                {} = Some({});",
903                        var_name, parse_expr
904                    )
905                    .unwrap();
906                }
907                writeln!(
908                    code,
909                    "                                #[cfg(feature = \"extra-children\")]"
910                )
911                .unwrap();
912                writeln!(
913                    code,
914                    "                                {{ child_idx += 1; }}"
915                )
916                .unwrap();
917                writeln!(code, "                            }}").unwrap();
918            }
919
920            // Capture or skip unknown elements (feature-gated)
921            writeln!(
922                code,
923                "                            #[cfg(feature = \"extra-children\")]"
924            )
925            .unwrap();
926            writeln!(code, "                            _ => {{").unwrap();
927            writeln!(
928                code,
929                "                                // Capture unknown element for roundtrip"
930            )
931            .unwrap();
932            writeln!(code, "                                let elem = RawXmlElement::from_reader(reader, &e)?;").unwrap();
933            writeln!(
934                code,
935                "                                extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
936            )
937            .unwrap();
938            writeln!(code, "                                child_idx += 1;").unwrap();
939            writeln!(code, "                            }}").unwrap();
940            writeln!(
941                code,
942                "                            #[cfg(not(feature = \"extra-children\"))]"
943            )
944            .unwrap();
945            writeln!(code, "                            _ => {{").unwrap();
946            writeln!(
947                code,
948                "                                // Skip unknown element"
949            )
950            .unwrap();
951            writeln!(
952                code,
953                "                                skip_element(reader)?;"
954            )
955            .unwrap();
956            writeln!(code, "                            }}").unwrap();
957            writeln!(code, "                        }}").unwrap();
958            writeln!(code, "                    }}").unwrap();
959            writeln!(code, "                    Event::Empty(e) => {{").unwrap();
960            writeln!(
961                code,
962                "                        match e.local_name().as_ref() {{"
963            )
964            .unwrap();
965
966            // Track matched element names to avoid duplicate match arms
967            let mut matched_names_empty = std::collections::HashSet::new();
968            for field in &elem_fields {
969                let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
970                let base_name = base_name.trim_start_matches('_');
971                let var_name = format!("f_{}", base_name);
972                let parse_expr = self.gen_element_parse_code(field, true);
973
974                // Add cfg attribute for feature-gated fields
975                if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
976                    writeln!(
977                        code,
978                        "                            #[cfg(feature = \"{}\")]",
979                        feature
980                    )
981                    .unwrap();
982                }
983                if self.is_eg_content_field(field) {
984                    // EG content field: match all variant element names (dedup across fields)
985                    let mut variant_names = Vec::new();
986                    let mut visited = std::collections::HashSet::new();
987                    if let Some(def_pattern) = self.definitions.get(field.xml_name.as_str()) {
988                        self.collect_element_variant_names(
989                            def_pattern,
990                            &mut variant_names,
991                            &mut visited,
992                        );
993                    }
994                    variant_names.retain(|n| matched_names_empty.insert(n.clone()));
995                    if !variant_names.is_empty() {
996                        let arms: Vec<_> = variant_names
997                            .iter()
998                            .map(|n| format!("b\"{}\"", n))
999                            .collect();
1000                        writeln!(
1001                            code,
1002                            "                            {} => {{",
1003                            arms.join(" | ")
1004                        )
1005                        .unwrap();
1006                    } else {
1007                        // All variants already matched by earlier field — skip
1008                        continue;
1009                    }
1010                } else {
1011                    matched_names_empty.insert(field.xml_name.clone());
1012                    writeln!(
1013                        code,
1014                        "                            b\"{}\" => {{",
1015                        field.xml_name
1016                    )
1017                    .unwrap();
1018                }
1019                if field.is_vec {
1020                    writeln!(
1021                        code,
1022                        "                                {}.push({});",
1023                        var_name, parse_expr
1024                    )
1025                    .unwrap();
1026                } else {
1027                    writeln!(
1028                        code,
1029                        "                                {} = Some({});",
1030                        var_name, parse_expr
1031                    )
1032                    .unwrap();
1033                }
1034                writeln!(
1035                    code,
1036                    "                                #[cfg(feature = \"extra-children\")]"
1037                )
1038                .unwrap();
1039                writeln!(
1040                    code,
1041                    "                                {{ child_idx += 1; }}"
1042                )
1043                .unwrap();
1044                writeln!(code, "                            }}").unwrap();
1045            }
1046
1047            // Capture or skip unknown empty elements (feature-gated)
1048            writeln!(
1049                code,
1050                "                            #[cfg(feature = \"extra-children\")]"
1051            )
1052            .unwrap();
1053            writeln!(code, "                            _ => {{").unwrap();
1054            writeln!(
1055                code,
1056                "                                // Capture unknown empty element for roundtrip"
1057            )
1058            .unwrap();
1059            writeln!(
1060                code,
1061                "                                let elem = RawXmlElement::from_empty(&e);"
1062            )
1063            .unwrap();
1064            writeln!(
1065                code,
1066                "                                extra_children.push(PositionedNode::new(child_idx, RawXmlNode::Element(elem)));"
1067            )
1068            .unwrap();
1069            writeln!(code, "                                child_idx += 1;").unwrap();
1070            writeln!(code, "                            }}").unwrap();
1071            writeln!(
1072                code,
1073                "                            #[cfg(not(feature = \"extra-children\"))]"
1074            )
1075            .unwrap();
1076            writeln!(code, "                            _ => {{}}").unwrap();
1077            writeln!(code, "                        }}").unwrap();
1078            writeln!(code, "                    }}").unwrap();
1079
1080            // Handle text content if any text fields.
1081            // Text may arrive split across multiple Text events (e.g. when entity
1082            // references like &amp; are interleaved), so we accumulate with push_str.
1083            // GeneralRef events carry entity references that quick-xml does not
1084            // expand inline (e.g. &amp; → "amp"); resolve them the same way.
1085            if !text_fields.is_empty() {
1086                writeln!(code, "                    Event::Text(e) => {{").unwrap();
1087                writeln!(
1088                    code,
1089                    "                        let s = e.decode().unwrap_or_default();"
1090                )
1091                .unwrap();
1092                for field in &text_fields {
1093                    let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1094                    let base_name = base_name.trim_start_matches('_');
1095                    let var_name = format!("f_{}", base_name);
1096                    writeln!(
1097                        code,
1098                        "                        {}.get_or_insert_with(String::new).push_str(&s);",
1099                        var_name
1100                    )
1101                    .unwrap();
1102                }
1103                writeln!(code, "                    }}").unwrap();
1104                writeln!(code, "                    Event::GeneralRef(e) => {{").unwrap();
1105                writeln!(
1106                    code,
1107                    "                        let name = e.decode().unwrap_or_default();"
1108                )
1109                .unwrap();
1110                writeln!(code, "                        if let Some(s) = quick_xml::escape::resolve_xml_entity(&name) {{").unwrap();
1111                for field in &text_fields {
1112                    let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1113                    let base_name = base_name.trim_start_matches('_');
1114                    let var_name = format!("f_{}", base_name);
1115                    writeln!(
1116                        code,
1117                        "                            {}.get_or_insert_with(String::new).push_str(s);",
1118                        var_name
1119                    ).unwrap();
1120                }
1121                writeln!(code, "                        }}").unwrap();
1122                writeln!(code, "                    }}").unwrap();
1123            }
1124
1125            writeln!(code, "                    Event::End(_) => break,").unwrap();
1126            writeln!(code, "                    Event::Eof => break,").unwrap();
1127            writeln!(code, "                    _ => {{}}").unwrap();
1128            writeln!(code, "                }}").unwrap();
1129            writeln!(code, "                buf.clear();").unwrap();
1130            writeln!(code, "            }}").unwrap();
1131            writeln!(code, "        }}").unwrap();
1132        } else {
1133            // No child elements, but still need to read to end tag if not empty
1134            writeln!(code).unwrap();
1135            writeln!(code, "        if !is_empty {{").unwrap();
1136            writeln!(code, "            let mut buf = Vec::new();").unwrap();
1137            writeln!(code, "            loop {{").unwrap();
1138            writeln!(
1139                code,
1140                "                match reader.read_event_into(&mut buf)? {{"
1141            )
1142            .unwrap();
1143            writeln!(code, "                    Event::End(_) => break,").unwrap();
1144            writeln!(code, "                    Event::Eof => break,").unwrap();
1145            writeln!(code, "                    _ => {{}}").unwrap();
1146            writeln!(code, "                }}").unwrap();
1147            writeln!(code, "                buf.clear();").unwrap();
1148            writeln!(code, "            }}").unwrap();
1149            writeln!(code, "        }}").unwrap();
1150        }
1151
1152        // Build result struct - use original field names
1153        writeln!(code).unwrap();
1154        writeln!(code, "        Ok(Self {{").unwrap();
1155        for field in &fields {
1156            let base_name = field.name.strip_prefix("r#").unwrap_or(&field.name);
1157            let base_name = base_name.trim_start_matches('_');
1158            let var_name = format!("f_{}", base_name);
1159
1160            // Add cfg attribute for feature-gated fields
1161            if let Some(ref feature) = self.get_field_feature(&rust_name, &field.xml_name) {
1162                writeln!(code, "            #[cfg(feature = \"{}\")]", feature).unwrap();
1163            }
1164
1165            // EG content fields that are required in schema are still Option<Box<...>>
1166            // in Rust for Default compatibility (see codegen.rs eg_needs_option).
1167            let eg_needs_option =
1168                self.is_eg_content_field(field) && !field.is_optional && !field.is_vec;
1169
1170            if field.is_optional || field.is_vec || eg_needs_option {
1171                writeln!(code, "            {}: {},", field.name, var_name).unwrap();
1172            } else {
1173                // Required field - unwrap with error
1174                writeln!(
1175                    code,
1176                    "            {}: {}.ok_or_else(|| ParseError::MissingAttribute(\"{}\".to_string()))?,",
1177                    field.name, var_name, field.xml_name
1178                )
1179                .unwrap();
1180            }
1181        }
1182        // Add extra_attrs if this struct has attributes (feature-gated)
1183        if has_attrs {
1184            writeln!(code, "            #[cfg(feature = \"extra-attrs\")]").unwrap();
1185            writeln!(code, "            extra_attrs,").unwrap();
1186        }
1187        // Add extra_children if this struct has a parsing loop (feature-gated)
1188        if has_parsing_loop {
1189            writeln!(code, "            #[cfg(feature = \"extra-children\")]").unwrap();
1190            writeln!(code, "            extra_children,").unwrap();
1191        }
1192        writeln!(code, "        }})").unwrap();
1193        writeln!(code, "    }}").unwrap();
1194        writeln!(code, "}}").unwrap();
1195
1196        Some(code)
1197    }
1198
1199    fn gen_attr_parse_expr(&self, pattern: &Pattern) -> String {
1200        match pattern {
1201            Pattern::Datatype { library, name, .. } if library == "xsd" => match name.as_str() {
1202                "boolean" => "Some(val == \"true\" || val == \"1\")".to_string(),
1203                "integer" | "int" | "long" | "short" | "byte" => "val.parse().ok()".to_string(),
1204                "unsignedInt" | "unsignedLong" | "unsignedShort" | "unsignedByte" => {
1205                    "val.parse().ok()".to_string()
1206                }
1207                "double" | "float" | "decimal" => "val.parse().ok()".to_string(),
1208                "hexBinary" => "decode_hex(&val)".to_string(),
1209                "base64Binary" => "decode_base64(&val)".to_string(),
1210                _ => "Some(val.into_owned())".to_string(),
1211            },
1212            Pattern::Ref(name) => {
1213                // First recurse to find what this ref resolves to
1214                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1215                    return self.gen_attr_parse_expr(def_pattern);
1216                }
1217                // Unknown ref - if it looks like an enum (ST_), use FromStr, otherwise string
1218                if name.contains("_ST_") {
1219                    "val.parse().ok()".to_string()
1220                } else {
1221                    "Some(val.into_owned())".to_string()
1222                }
1223            }
1224            // String choice enums
1225            Pattern::Choice(variants)
1226                if variants
1227                    .iter()
1228                    .all(|v| matches!(v, Pattern::StringLiteral(_))) =>
1229            {
1230                "val.parse().ok()".to_string()
1231            }
1232            _ => "Some(val.into_owned())".to_string(),
1233        }
1234    }
1235
1236    fn extract_fields(&self, pattern: &Pattern) -> Vec<Field> {
1237        let mut fields = Vec::new();
1238        self.collect_fields(pattern, &mut fields, false);
1239        let mut seen = std::collections::HashSet::new();
1240        fields.retain(|f| seen.insert(f.name.clone()));
1241        fields
1242    }
1243
1244    fn collect_fields(&self, pattern: &Pattern, fields: &mut Vec<Field>, is_optional: bool) {
1245        match pattern {
1246            Pattern::Attribute { name, pattern } => {
1247                fields.push(Field {
1248                    name: self.qname_to_field_name(name),
1249                    xml_name: name.local.clone(),
1250                    xml_prefix: name.prefix.clone(),
1251                    pattern: pattern.as_ref().clone(),
1252                    is_optional,
1253                    is_attribute: true,
1254                    is_vec: false,
1255                    is_text_content: false,
1256                });
1257            }
1258            Pattern::Element { name, pattern } => {
1259                // Skip wildcard elements (element * { ... }) — handled by extra_children
1260                if name.local == "_any" {
1261                    return;
1262                }
1263                fields.push(Field {
1264                    name: self.qname_to_field_name(name),
1265                    xml_name: name.local.clone(),
1266                    xml_prefix: name.prefix.clone(),
1267                    pattern: pattern.as_ref().clone(),
1268                    is_optional,
1269                    is_attribute: false,
1270                    is_vec: false,
1271                    is_text_content: false,
1272                });
1273            }
1274            Pattern::Sequence(items) | Pattern::Interleave(items) => {
1275                for item in items {
1276                    self.collect_fields(item, fields, is_optional);
1277                }
1278            }
1279            Pattern::Optional(inner) => {
1280                self.collect_fields(inner, fields, true);
1281            }
1282            Pattern::ZeroOrMore(inner) | Pattern::OneOrMore(inner) => match inner.as_ref() {
1283                Pattern::Element { name, pattern } if name.local != "_any" => {
1284                    fields.push(Field {
1285                        name: self.qname_to_field_name(name),
1286                        xml_name: name.local.clone(),
1287                        xml_prefix: name.prefix.clone(),
1288                        pattern: pattern.as_ref().clone(),
1289                        is_optional: false,
1290                        is_attribute: false,
1291                        is_vec: true,
1292                        is_text_content: false,
1293                    });
1294                }
1295                Pattern::Ref(name) if name.contains("_EG_") => {
1296                    if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1297                        if self.is_element_choice(def_pattern) {
1298                            // Element choice → Vec<Box<EGType>> field
1299                            fields.push(Field {
1300                                name: self.eg_ref_to_field_name(name),
1301                                xml_name: name.clone(),
1302                                xml_prefix: None,
1303                                pattern: Pattern::Ref(name.clone()),
1304                                is_optional: false,
1305                                is_attribute: false,
1306                                is_vec: true,
1307                                is_text_content: false,
1308                            });
1309                        } else {
1310                            // Struct-like → inline fields
1311                            self.collect_fields(def_pattern, fields, true);
1312                        }
1313                    }
1314                }
1315                Pattern::Choice(alternatives) => {
1316                    // ZeroOrMore(Choice([elements])) - each element can appear multiple times
1317                    for alt in alternatives {
1318                        self.collect_fields_as_vec(alt, fields);
1319                    }
1320                }
1321                Pattern::Ref(_) => {
1322                    self.collect_fields(inner, fields, false);
1323                }
1324                Pattern::Group(group_inner) => {
1325                    // Unwrap group and handle inner pattern
1326                    // For ZeroOrMore(Group(Choice([...]))) - treat each alternative as Vec
1327                    if let Pattern::Choice(alternatives) = group_inner.as_ref() {
1328                        for alt in alternatives {
1329                            self.collect_fields_as_vec(alt, fields);
1330                        }
1331                    } else {
1332                        self.collect_fields(group_inner, fields, false);
1333                    }
1334                }
1335                _ => {}
1336            },
1337            Pattern::Group(inner) => {
1338                self.collect_fields(inner, fields, is_optional);
1339            }
1340            Pattern::Ref(name) => {
1341                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1342                    if name.contains("_EG_") {
1343                        if self.is_element_choice(def_pattern) {
1344                            // Element choice → content field (Optional or Vec depending on context)
1345                            fields.push(Field {
1346                                name: self.eg_ref_to_field_name(name),
1347                                xml_name: name.clone(),
1348                                xml_prefix: None,
1349                                pattern: Pattern::Ref(name.clone()),
1350                                is_optional,
1351                                is_attribute: false,
1352                                is_vec: false,
1353                                is_text_content: false,
1354                            });
1355                        } else {
1356                            // Struct-like → inline fields
1357                            self.collect_fields(def_pattern, fields, is_optional);
1358                        }
1359                    } else if name.contains("_AG_") {
1360                        // Attribute group → inline attribute fields
1361                        self.collect_fields(def_pattern, fields, is_optional);
1362                    } else if self.is_string_type(def_pattern) {
1363                        // This is text content - always optional since elements
1364                        // can be self-closing (e.g. shared formula refs: <f t="shared" si="0"/>)
1365                        fields.push(Field {
1366                            name: "text".to_string(),
1367                            xml_name: "$text".to_string(),
1368                            xml_prefix: None,
1369                            pattern: Pattern::Datatype {
1370                                library: "xsd".to_string(),
1371                                name: "string".to_string(),
1372                                params: vec![],
1373                            },
1374                            is_optional: true,
1375                            is_attribute: false,
1376                            is_vec: false,
1377                            is_text_content: true,
1378                        });
1379                    } else {
1380                        // CT_* mixin or base type — inline its fields
1381                        self.collect_fields(def_pattern, fields, is_optional);
1382                    }
1383                }
1384            }
1385            Pattern::Choice(alternatives) => {
1386                // Flatten choice into optional fields.
1387                // In a choice, each alternative might not be selected, so all become optional.
1388                for alt in alternatives {
1389                    self.collect_fields(alt, fields, true);
1390                }
1391            }
1392            _ => {}
1393        }
1394    }
1395
1396    /// Collect fields as Vec (for elements inside ZeroOrMore(Choice([...])))
1397    /// Only non-optional elements become Vec; optional elements stay as Option.
1398    fn collect_fields_as_vec(&self, pattern: &Pattern, fields: &mut Vec<Field>) {
1399        match pattern {
1400            Pattern::Element {
1401                name,
1402                pattern: inner_pattern,
1403            } if name.local != "_any" => {
1404                fields.push(Field {
1405                    name: self.qname_to_field_name(name),
1406                    xml_name: name.local.clone(),
1407                    xml_prefix: name.prefix.clone(),
1408                    pattern: inner_pattern.as_ref().clone(),
1409                    is_optional: false,
1410                    is_attribute: false,
1411                    is_vec: true,
1412                    is_text_content: false,
1413                });
1414            }
1415            Pattern::Optional(inner) => {
1416                // Optional inside a repeating choice means element can appear 0-1 times,
1417                // NOT multiple times. Delegate to collect_fields with is_optional=true.
1418                self.collect_fields(inner, fields, true);
1419            }
1420            Pattern::Group(inner) => {
1421                self.collect_fields_as_vec(inner, fields);
1422            }
1423            Pattern::Ref(name) => {
1424                // Ref inside a repeating choice - create Vec<RefType> field
1425                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1426                    if name.contains("_EG_") && self.is_element_choice(def_pattern) {
1427                        // EG_* element group → Vec<EGType>
1428                        fields.push(Field {
1429                            name: self.eg_ref_to_field_name(name),
1430                            xml_name: name.clone(),
1431                            xml_prefix: None,
1432                            pattern: Pattern::Ref(name.clone()),
1433                            is_optional: false,
1434                            is_attribute: false,
1435                            is_vec: true,
1436                            is_text_content: false,
1437                        });
1438                    } else if !name.contains("_AG_") && !name.contains("_CT_") {
1439                        // Other refs that wrap elements
1440                        self.collect_fields_as_vec(def_pattern, fields);
1441                    }
1442                }
1443            }
1444            _ => {}
1445        }
1446    }
1447
1448    /// Check if a pattern resolves to a string type (for text content detection).
1449    fn is_string_type(&self, pattern: &Pattern) -> bool {
1450        match pattern {
1451            Pattern::Datatype { library, name, .. } => {
1452                library == "xsd" && (name == "string" || name == "token" || name == "NCName")
1453            }
1454            Pattern::Ref(name) => {
1455                // Check if the referenced type is a string type
1456                self.definitions
1457                    .get(name.as_str())
1458                    .is_some_and(|p| self.is_string_type(p))
1459            }
1460            _ => false,
1461        }
1462    }
1463
1464    fn to_rust_type_name(&self, name: &str) -> String {
1465        let spec_name = strip_namespace_prefix(name);
1466        if let Some(mappings) = &self.config.name_mappings
1467            && let Some(mapped) = mappings.resolve_type(&self.config.module_name, spec_name)
1468        {
1469            return mapped.to_string();
1470        }
1471        to_pascal_case(spec_name)
1472    }
1473
1474    /// Try to resolve a schema reference name to a cross-crate Rust type.
1475    /// Returns Some(full_path) if the name matches a configured prefix.
1476    fn resolve_cross_crate_type(&self, name: &str) -> Option<String> {
1477        for (prefix, (crate_path, module_name)) in &self.config.cross_crate_type_prefix {
1478            if name.starts_with(prefix) {
1479                // Convert schema name (a_CT_Color) to Rust type name using the cross-crate module's mappings
1480                let spec_name = strip_namespace_prefix(name);
1481                let rust_type_name = if let Some(mappings) = &self.config.name_mappings
1482                    && let Some(mapped) = mappings.resolve_type(module_name, spec_name)
1483                {
1484                    mapped.to_string()
1485                } else {
1486                    to_pascal_case(spec_name)
1487                };
1488                return Some(format!("{}{}", crate_path, rust_type_name));
1489            }
1490        }
1491        None
1492    }
1493
1494    fn to_rust_variant_name(&self, name: &str) -> String {
1495        if name.is_empty() {
1496            return "Empty".to_string();
1497        }
1498        if let Some(mappings) = &self.config.name_mappings
1499            && let Some(mapped) = mappings.resolve_variant(&self.config.module_name, name)
1500        {
1501            return mapped.to_string();
1502        }
1503        let name = to_pascal_case(name);
1504        if name.chars().next().is_some_and(|c| c.is_ascii_digit()) {
1505            format!("_{}", name)
1506        } else {
1507            name
1508        }
1509    }
1510
1511    fn qname_to_field_name(&self, qname: &QName) -> String {
1512        if let Some(mappings) = &self.config.name_mappings
1513            && let Some(mapped) = mappings.resolve_field(&self.config.module_name, &qname.local)
1514        {
1515            return mapped.to_string();
1516        }
1517        to_snake_case(&qname.local)
1518    }
1519
1520    /// Get the feature name for a field if it requires feature gating.
1521    /// Returns None if the field is "core" (always included) or unmapped.
1522    fn get_field_feature(&self, struct_name: &str, xml_field_name: &str) -> Option<String> {
1523        self.config
1524            .feature_mappings
1525            .as_ref()
1526            .and_then(|fm| {
1527                fm.primary_feature(&self.config.module_name, struct_name, xml_field_name)
1528            })
1529            .map(|feature| format!("{}-{}", self.config.module_name, feature))
1530    }
1531
1532    /// Check if a definition is an element-wrapper type alias (Element { pattern: Ref(...) }).
1533    /// These generate `pub type Foo = Box<T>;` and should not be double-boxed when used.
1534    fn is_element_wrapper_type_alias(&self, name: &str) -> bool {
1535        if let Some(def_pattern) = self.definitions.get(name) {
1536            matches!(def_pattern, Pattern::Element { pattern, .. } if matches!(pattern.as_ref(), Pattern::Ref(_)))
1537        } else {
1538            false
1539        }
1540    }
1541
1542    /// Convert a pattern to Rust type and boxing requirement.
1543    /// - `is_vec`: if true, don't indicate boxing needed (Vec provides heap indirection)
1544    fn pattern_to_rust_type(&self, pattern: &Pattern, is_vec: bool) -> (String, bool) {
1545        match pattern {
1546            Pattern::Ref(name) => {
1547                if self.definitions.contains_key(name.as_str()) {
1548                    let type_name = self.to_rust_type_name(name);
1549                    // Box CT_* and EG_* types, but not in Vec context (Vec provides heap indirection)
1550                    // Also don't box element-wrapper type aliases - they're already Box<T>
1551                    let is_complex = name.contains("_CT_") || name.contains("_EG_");
1552                    let is_already_boxed = self.is_element_wrapper_type_alias(name);
1553                    let needs_box = is_complex && !is_vec && !is_already_boxed;
1554                    (type_name, needs_box)
1555                } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1556                    // Cross-crate type - box CT_* or EG_*, but not in Vec context
1557                    let is_complex = name.contains("_CT_") || name.contains("_EG_");
1558                    let needs_box = is_complex && !is_vec;
1559                    (cross_crate, needs_box)
1560                } else {
1561                    ("String".to_string(), false)
1562                }
1563            }
1564            Pattern::Datatype { library, name, .. } => {
1565                (xsd_to_rust(library, name).to_string(), false)
1566            }
1567            Pattern::Empty => ("()".to_string(), false),
1568            Pattern::StringLiteral(_) => ("String".to_string(), false),
1569            Pattern::Choice(_) => ("String".to_string(), false),
1570            _ => ("String".to_string(), false),
1571        }
1572    }
1573
1574    /// Generate code to parse a child element field.
1575    /// Returns the expression that produces the parsed value.
1576    fn gen_element_parse_code(&self, field: &Field, is_empty_element: bool) -> String {
1577        // Pass is_vec to avoid boxing in Vec contexts
1578        let (rust_type, needs_box) = self.pattern_to_rust_type(&field.pattern, field.is_vec);
1579        let strategy = self.get_parse_strategy(&field.pattern);
1580
1581        let parse_expr = match strategy {
1582            ParseStrategy::FromXml => {
1583                // For type aliases, we need to find the actual type that has FromXml impl
1584                // and check if the type alias already includes a Box
1585                let (actual_type, type_alias_has_box) =
1586                    self.resolve_from_xml_type_with_box(&field.pattern);
1587                let final_type = actual_type.unwrap_or(rust_type.clone());
1588
1589                let mut expr = format!(
1590                    "{}::from_xml(reader, &e, {})?",
1591                    final_type, is_empty_element
1592                );
1593
1594                // If the type alias is like `type X = Box<Y>`, we need a Box for that
1595                if type_alias_has_box {
1596                    expr = format!("Box::new({})", expr);
1597                }
1598
1599                // If the field type is `Box<X>`, we need another Box for the field
1600                if needs_box {
1601                    expr = format!("Box::new({})", expr);
1602                }
1603
1604                return expr;
1605            }
1606            ParseStrategy::TextFromStr => {
1607                if is_empty_element {
1608                    // Empty element with FromStr - try to parse empty string or use default
1609                    "Default::default()".to_string()
1610                } else {
1611                    "{ let text = read_text_content(reader)?; text.parse().map_err(|_| ParseError::InvalidValue(text))? }".to_string()
1612                }
1613            }
1614            ParseStrategy::TextString => {
1615                if is_empty_element {
1616                    "String::new()".to_string()
1617                } else {
1618                    "read_text_content(reader)?".to_string()
1619                }
1620            }
1621            ParseStrategy::TextHexBinary => {
1622                if is_empty_element {
1623                    "Vec::new()".to_string()
1624                } else {
1625                    "{ let text = read_text_content(reader)?; decode_hex(&text).unwrap_or_default() }".to_string()
1626                }
1627            }
1628            ParseStrategy::TextBase64Binary => {
1629                if is_empty_element {
1630                    "Vec::new()".to_string()
1631                } else {
1632                    "{ let text = read_text_content(reader)?; decode_base64(&text).unwrap_or_default() }".to_string()
1633                }
1634            }
1635        };
1636
1637        // For non-FromXml strategies, handle boxing normally
1638        if strategy != ParseStrategy::FromXml && needs_box {
1639            format!("Box::new({})", parse_expr)
1640        } else {
1641            parse_expr
1642        }
1643    }
1644
1645    /// Resolve a pattern to the actual type that has a FromXml impl.
1646    /// Returns (Option<type_name>, type_alias_already_has_box).
1647    /// For type aliases (definitions that are just Pattern::Element wrapping a ref),
1648    /// returns the underlying type's Rust name and indicates the alias includes a Box.
1649    fn resolve_from_xml_type_with_box(&self, pattern: &Pattern) -> (Option<String>, bool) {
1650        match pattern {
1651            Pattern::Ref(name) => {
1652                // Look up the definition
1653                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1654                    // Skip inline attribute refs (like r_id) - they don't have FromXml impls
1655                    if self.is_inline_attribute_ref(name, def_pattern) {
1656                        return (None, false);
1657                    }
1658                    // If it's a type alias (Pattern::Element wrapping another ref),
1659                    // the generated type will be `type X = Box<InnerType>` for CT_*/EG_* inner types
1660                    // So we resolve to the inner type and signal boxing status
1661                    if let Pattern::Element { pattern: inner, .. } = def_pattern
1662                        && let Some(inner_type) = self.resolve_from_xml_type_simple(inner)
1663                    {
1664                        // Check if the inner ref is to a CT_* or EG_* type (which gets boxed)
1665                        let type_alias_has_box = if let Pattern::Ref(inner_name) = inner.as_ref() {
1666                            inner_name.contains("_CT_") || inner_name.contains("_EG_")
1667                        } else {
1668                            false
1669                        };
1670                        return (Some(inner_type), type_alias_has_box);
1671                    }
1672                    // CT_* types that are NOT type aliases have their own FromXml impl
1673                    // (generated as structs), even if schema defines them as `CT_Foo = EG_Bar`.
1674                    // Don't resolve through - use the CT type directly.
1675                    if name.contains("_CT_") {
1676                        return (Some(self.to_rust_type_name(name)), false);
1677                    }
1678                    // If it's a simple ref, just a type alias like `type X = Y`
1679                    // Check if the inner ref is external (not in our definitions)
1680                    if let Pattern::Ref(inner_name) = def_pattern
1681                        && !self.definitions.contains_key(inner_name.as_str())
1682                    {
1683                        // External ref - check if it's a cross-crate type
1684                        if let Some(cross_crate) = self.resolve_cross_crate_type(inner_name) {
1685                            return (Some(cross_crate), false);
1686                        }
1687                        // Otherwise don't try to resolve, use original type
1688                        return (None, false);
1689                    } else if let Pattern::Ref(inner_name) = def_pattern {
1690                        return self
1691                            .resolve_from_xml_type_with_box(&Pattern::Ref(inner_name.clone()));
1692                    }
1693                } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1694                    // Not in local definitions but matches a cross-crate prefix
1695                    return (Some(cross_crate), false);
1696                }
1697                // Type in definitions - use its name
1698                (Some(self.to_rust_type_name(name)), false)
1699            }
1700            _ => (None, false),
1701        }
1702    }
1703
1704    /// Simple resolver that just returns the type name without box tracking.
1705    fn resolve_from_xml_type_simple(&self, pattern: &Pattern) -> Option<String> {
1706        match pattern {
1707            Pattern::Ref(name) => {
1708                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1709                    if let Pattern::Element { pattern: inner, .. } = def_pattern {
1710                        return self.resolve_from_xml_type_simple(inner);
1711                    }
1712                    if let Pattern::Ref(inner_name) = def_pattern {
1713                        // Check if the inner ref is external
1714                        if !self.definitions.contains_key(inner_name.as_str()) {
1715                            // External ref - check if it's a cross-crate type
1716                            if let Some(cross_crate) = self.resolve_cross_crate_type(inner_name) {
1717                                return Some(cross_crate);
1718                            }
1719                            // Otherwise stop resolution
1720                            return None;
1721                        }
1722                        return self
1723                            .resolve_from_xml_type_simple(&Pattern::Ref(inner_name.clone()));
1724                    }
1725                } else if let Some(cross_crate) = self.resolve_cross_crate_type(name) {
1726                    // Not in local definitions but matches a cross-crate prefix
1727                    return Some(cross_crate);
1728                }
1729                Some(self.to_rust_type_name(name))
1730            }
1731            _ => None,
1732        }
1733    }
1734
1735    /// Determine how to parse a field's value from XML.
1736    fn get_parse_strategy(&self, pattern: &Pattern) -> ParseStrategy {
1737        match pattern {
1738            Pattern::Ref(name) => {
1739                // Complex types and element groups always use FromXml
1740                if name.contains("_CT_") || name.contains("_EG_") {
1741                    return ParseStrategy::FromXml;
1742                }
1743
1744                // Check what this ref resolves to
1745                if let Some(def_pattern) = self.definitions.get(name.as_str()) {
1746                    // If it's a ref to another ref (like CT_Drawing = r_id),
1747                    // and that ref is external (not in our definitions), treat as empty struct
1748                    if let Pattern::Ref(inner_name) = def_pattern
1749                        && !self.definitions.contains_key(inner_name.as_str())
1750                    {
1751                        // External ref - check if it's a cross-crate CT/EG type
1752                        if inner_name.contains("_CT_") || inner_name.contains("_EG_") {
1753                            return ParseStrategy::FromXml;
1754                        }
1755                        // External ref (e.g., r_id from another schema)
1756                        // These generate empty structs that need simple FromXml impls
1757                        return ParseStrategy::FromXml;
1758                    }
1759                    return self.get_parse_strategy(def_pattern);
1760                } else if self.resolve_cross_crate_type(name).is_some() {
1761                    // Cross-crate type - use FromXml
1762                    return ParseStrategy::FromXml;
1763                }
1764
1765                // Unknown ref - treat as string
1766                ParseStrategy::TextString
1767            }
1768            Pattern::Datatype { library, name, .. } => {
1769                if library == "xsd" {
1770                    match name.as_str() {
1771                        "string" | "token" | "NCName" | "ID" | "IDREF" | "anyURI" | "dateTime"
1772                        | "date" | "time" => ParseStrategy::TextString,
1773                        "hexBinary" => ParseStrategy::TextHexBinary,
1774                        "base64Binary" => ParseStrategy::TextBase64Binary,
1775                        // Numbers and booleans use FromStr
1776                        _ => ParseStrategy::TextFromStr,
1777                    }
1778                } else {
1779                    ParseStrategy::TextString
1780                }
1781            }
1782            // String enums use FromStr
1783            Pattern::Choice(variants)
1784                if variants
1785                    .iter()
1786                    .all(|v| matches!(v, Pattern::StringLiteral(_))) =>
1787            {
1788                ParseStrategy::TextFromStr
1789            }
1790            Pattern::StringLiteral(_) => ParseStrategy::TextString,
1791            Pattern::Empty => ParseStrategy::TextString,
1792            Pattern::List(_) => ParseStrategy::TextString,
1793            // For complex patterns (Sequence, etc.), assume it needs from_xml
1794            _ => ParseStrategy::FromXml,
1795        }
1796    }
1797}
1798
1799pub(crate) struct Field {
1800    pub name: String,
1801    pub xml_name: String,
1802    pub xml_prefix: Option<String>,
1803    pub pattern: Pattern,
1804    pub is_optional: bool,
1805    pub is_attribute: bool,
1806    pub is_vec: bool,
1807    pub is_text_content: bool,
1808}
1809
1810pub(crate) fn strip_namespace_prefix(name: &str) -> &str {
1811    for kind in ["CT_", "ST_", "EG_"] {
1812        if let Some(pos) = name.find(kind)
1813            && pos > 0
1814        {
1815            return &name[pos..];
1816        }
1817    }
1818    name
1819}
1820
1821pub(crate) fn to_pascal_case(s: &str) -> String {
1822    let mut result = String::new();
1823    let mut capitalize_next = true;
1824    for ch in s.chars() {
1825        if ch == '_' || ch == '-' {
1826            capitalize_next = true;
1827        } else if capitalize_next {
1828            result.extend(ch.to_uppercase());
1829            capitalize_next = false;
1830        } else {
1831            result.push(ch);
1832        }
1833    }
1834    result
1835}
1836
1837pub(crate) fn to_snake_case(s: &str) -> String {
1838    let mut result = String::new();
1839    for (i, ch) in s.chars().enumerate() {
1840        if ch.is_uppercase() && i > 0 {
1841            result.push('_');
1842        }
1843        result.extend(ch.to_lowercase());
1844    }
1845    match result.as_str() {
1846        // Rust keywords
1847        "type" => "r#type".to_string(),
1848        "ref" => "r#ref".to_string(),
1849        "match" => "r#match".to_string(),
1850        "in" => "r#in".to_string(),
1851        "for" => "r#for".to_string(),
1852        "macro" => "r#macro".to_string(),
1853        "if" => "r#if".to_string(),
1854        "else" => "r#else".to_string(),
1855        "loop" => "r#loop".to_string(),
1856        "break" => "r#break".to_string(),
1857        "continue" => "r#continue".to_string(),
1858        "return" => "r#return".to_string(),
1859        "self" => "r#self".to_string(),
1860        "super" => "r#super".to_string(),
1861        "crate" => "r#crate".to_string(),
1862        "mod" => "r#mod".to_string(),
1863        "pub" => "r#pub".to_string(),
1864        "use" => "r#use".to_string(),
1865        "as" => "r#as".to_string(),
1866        "static" => "r#static".to_string(),
1867        "const" => "r#const".to_string(),
1868        "extern" => "r#extern".to_string(),
1869        "fn" => "r#fn".to_string(),
1870        "struct" => "r#struct".to_string(),
1871        "enum" => "r#enum".to_string(),
1872        "trait" => "r#trait".to_string(),
1873        "impl" => "r#impl".to_string(),
1874        "where" => "r#where".to_string(),
1875        "async" => "r#async".to_string(),
1876        "await" => "r#await".to_string(),
1877        "move" => "r#move".to_string(),
1878        "box" => "r#box".to_string(),
1879        "dyn" => "r#dyn".to_string(),
1880        "abstract" => "r#abstract".to_string(),
1881        "become" => "r#become".to_string(),
1882        "do" => "r#do".to_string(),
1883        "final" => "r#final".to_string(),
1884        "override" => "r#override".to_string(),
1885        "priv" => "r#priv".to_string(),
1886        "typeof" => "r#typeof".to_string(),
1887        "unsized" => "r#unsized".to_string(),
1888        "virtual" => "r#virtual".to_string(),
1889        "yield" => "r#yield".to_string(),
1890        "try" => "r#try".to_string(),
1891        _ => result,
1892    }
1893}
1894
1895pub(crate) fn xsd_to_rust(library: &str, name: &str) -> &'static str {
1896    if library == "xsd" {
1897        match name {
1898            "string" => "String",
1899            "integer" => "i64",
1900            "int" => "i32",
1901            "long" => "i64",
1902            "short" => "i16",
1903            "byte" => "i8",
1904            "unsignedInt" => "u32",
1905            "unsignedLong" => "u64",
1906            "unsignedShort" => "u16",
1907            "unsignedByte" => "u8",
1908            "boolean" => "bool",
1909            "double" => "f64",
1910            "float" => "f32",
1911            "decimal" => "f64",
1912            "hexBinary" | "base64Binary" => "Vec<u8>",
1913            _ => "String",
1914        }
1915    } else {
1916        "String"
1917    }
1918}