facet_xml/
deserialize.rs

1//! XML deserialization using quick-xml streaming events.
2//!
3//! This deserializer uses quick-xml's event-based API, processing events
4//! on-demand and supporting rewind via event indices for flatten deserialization.
5
6use base64::Engine;
7use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
8use facet_core::{
9    Def, EnumType, Facet, Field, NumericType, PrimitiveType, ShapeLayout, StructKind, StructType,
10    Type, UserType, Variant,
11};
12use facet_reflect::{Partial, is_spanned_shape};
13use facet_solver::{PathSegment, Schema, Solver};
14use miette::SourceSpan;
15use quick_xml::escape::resolve_xml_entity;
16use quick_xml::events::{BytesStart, Event};
17use quick_xml::name::ResolveResult;
18use quick_xml::reader::NsReader;
19
20use crate::annotation::{XmlAnnotationPhase, fields_missing_xml_annotations};
21use crate::error::{MissingAnnotationPhase, XmlError, XmlErrorKind};
22
23pub(crate) type Result<T> = std::result::Result<T, XmlError>;
24
25// ============================================================================
26// Deserialize Options
27// ============================================================================
28
29/// Options for controlling XML deserialization behavior.
30///
31/// # Example
32///
33/// ```
34/// use facet::Facet;
35/// use facet_xml::{self as xml, DeserializeOptions};
36///
37/// #[derive(Facet, Debug, PartialEq)]
38/// struct Person {
39///     #[facet(xml::attribute)]
40///     name: String,
41/// }
42///
43/// let xml_str = r#"<Person name="Alice" extra="unknown"/>"#;
44///
45/// // Without options: unknown attributes are silently ignored
46/// let person: Person = xml::from_str(xml_str).unwrap();
47/// assert_eq!(person.name, "Alice");
48///
49/// // With deny_unknown_fields: unknown attributes cause an error
50/// let options = DeserializeOptions::default().deny_unknown_fields(true);
51/// let result: Result<Person, _> = xml::from_str_with_options(xml_str, &options);
52/// assert!(result.is_err());
53/// ```
54#[derive(Debug, Clone, Default)]
55pub struct DeserializeOptions {
56    /// If `true`, reject XML documents with unknown attributes or elements
57    /// that don't correspond to any field in the target struct.
58    ///
59    /// When `false` (the default), unknown attributes and elements are
60    /// silently ignored.
61    ///
62    /// This option is combined with any `#[facet(deny_unknown_fields)]`
63    /// attribute on the struct - if either is set, unknown fields cause
64    /// an error.
65    pub deny_unknown_fields: bool,
66}
67
68impl DeserializeOptions {
69    /// Create new options with default values.
70    pub fn new() -> Self {
71        Self::default()
72    }
73
74    /// Set whether to deny unknown fields.
75    ///
76    /// When enabled, deserialization will fail if the XML contains
77    /// attributes or elements that don't match any field in the struct.
78    pub fn deny_unknown_fields(mut self, deny: bool) -> Self {
79        self.deny_unknown_fields = deny;
80        self
81    }
82}
83
84/// Get the display name for a variant (respecting `rename` attribute).
85fn get_variant_display_name(variant: &Variant) -> &'static str {
86    if let Some(attr) = variant.get_builtin_attr("rename")
87        && let Some(&renamed) = attr.get_as::<&str>()
88    {
89        return renamed;
90    }
91    variant.name
92}
93
94/// Get the display name for a shape (respecting `rename` attribute).
95pub(crate) fn get_shape_display_name(shape: &facet_core::Shape) -> &'static str {
96    if let Some(renamed) = shape.get_builtin_attr_value::<&str>("rename") {
97        return renamed;
98    }
99    shape.type_identifier
100}
101
102/// Get the display name for a field (respecting `rename` attribute).
103fn get_field_display_name(field: &Field) -> &'static str {
104    if let Some(attr) = field.get_builtin_attr("rename")
105        && let Some(&renamed) = attr.get_as::<&str>()
106    {
107        return renamed;
108    }
109    field.name
110}
111
112/// Extract the local name from a potentially prefixed name.
113///
114/// For example: `"android:name"` -> `"name"`, `"name"` -> `"name"`
115///
116/// This handles the case where field names use `rename = "prefix:localname"`
117/// to match elements/attributes with a specific prefix in the document.
118fn local_name_of(name: &str) -> &str {
119    // Use rsplit_once to handle names with multiple colons correctly
120    // (though that's unusual in XML)
121    name.rsplit_once(':')
122        .map(|(_, local)| local)
123        .unwrap_or(name)
124}
125
126/// Check if a shape can accept an element with the given name.
127/// For structs: element name must match struct's display name.
128/// For enums: element name must match one of the variant's display names.
129fn shape_accepts_element(shape: &facet_core::Shape, element_name: &str) -> bool {
130    match &shape.ty {
131        Type::User(UserType::Enum(enum_type)) => {
132            // For enums, check if element name matches any variant
133            enum_type
134                .variants
135                .iter()
136                .any(|v| get_variant_display_name(v) == element_name)
137        }
138        Type::User(UserType::Struct(_)) => {
139            // For structs, check if element name matches struct's name
140            get_shape_display_name(shape) == element_name
141        }
142        _ => {
143            // For other types (opaque, etc.), use type identifier
144            shape.type_identifier == element_name
145        }
146    }
147}
148
149/// Get the list item shape from a field's shape (if it's a list type).
150fn get_list_item_shape(shape: &facet_core::Shape) -> Option<&'static facet_core::Shape> {
151    match &shape.def {
152        Def::List(list_def) => Some(list_def.t()),
153        _ => None,
154    }
155}
156
157/// Check if the attribute is reserved for XML namespace
158fn is_xml_namespace_attribute(name: &quick_xml::name::QName<'_>) -> bool {
159    match name.prefix() {
160        Some(prefix) => prefix.as_ref() == b"xmlns",
161        None => name.local_name().as_ref() == b"xmlns",
162    }
163}
164
165// ============================================================================
166// Public API
167// ============================================================================
168
169/// Deserialize an XML string into a value of type `T`.
170///
171/// # Example
172///
173/// ```
174/// use facet::Facet;
175/// use facet_xml as xml;
176///
177/// #[derive(Facet, Debug, PartialEq)]
178/// struct Person {
179///     #[facet(xml::attribute)]
180///     id: u32,
181///     #[facet(xml::element)]
182///     name: String,
183/// }
184///
185/// let xml_str = r#"<Person id="42"><name>Alice</name></Person>"#;
186/// let person: Person = facet_xml::from_str(xml_str).unwrap();
187/// assert_eq!(person.name, "Alice");
188/// assert_eq!(person.id, 42);
189/// ```
190pub fn from_str<'input, 'facet, T>(xml: &'input str) -> Result<T>
191where
192    T: Facet<'facet>,
193    'input: 'facet,
194{
195    from_str_with_options(xml, &DeserializeOptions::default())
196}
197
198/// Deserialize an XML string into a value of type `T` with custom options.
199///
200/// # Example
201///
202/// ```
203/// use facet::Facet;
204/// use facet_xml::{self as xml, DeserializeOptions};
205///
206/// #[derive(Facet, Debug, PartialEq)]
207/// struct Person {
208///     #[facet(xml::attribute)]
209///     name: String,
210/// }
211///
212/// // With deny_unknown_fields, unknown attributes cause an error
213/// let options = DeserializeOptions::default().deny_unknown_fields(true);
214/// let xml_str = r#"<Person name="Alice" extra="unknown"/>"#;
215/// let result: Result<Person, _> = xml::from_str_with_options(xml_str, &options);
216/// assert!(result.is_err());
217///
218/// // Valid XML without unknown fields works fine
219/// let xml_str = r#"<Person name="Alice"/>"#;
220/// let person: Person = xml::from_str_with_options(xml_str, &options).unwrap();
221/// assert_eq!(person.name, "Alice");
222/// ```
223pub fn from_str_with_options<'input, 'facet, T>(
224    xml: &'input str,
225    options: &DeserializeOptions,
226) -> Result<T>
227where
228    T: Facet<'facet>,
229    'input: 'facet,
230{
231    log::trace!(
232        "from_str_with_options: parsing XML for type {}",
233        core::any::type_name::<T>()
234    );
235
236    let mut deserializer = XmlDeserializer::new(xml, options.clone())?;
237    let partial = Partial::alloc::<T>()?;
238
239    let partial = deserializer.deserialize_document(partial)?;
240
241    let result = partial
242        .build()
243        .map_err(|e| XmlError::new(XmlErrorKind::Reflect(e)).with_source(xml))?
244        .materialize()
245        .map_err(|e| XmlError::new(XmlErrorKind::Reflect(e)).with_source(xml))?;
246
247    Ok(result)
248}
249
250/// Deserialize an XML byte slice into a value of type `T`.
251///
252/// This is a convenience wrapper around [`from_str`] that first validates
253/// that the input is valid UTF-8.
254///
255/// # Example
256///
257/// ```
258/// use facet::Facet;
259/// use facet_xml as xml;
260///
261/// #[derive(Facet, Debug, PartialEq)]
262/// struct Person {
263///     #[facet(xml::attribute)]
264///     id: u32,
265///     #[facet(xml::element)]
266///     name: String,
267/// }
268///
269/// let xml_bytes = b"<Person id=\"42\"><name>Alice</name></Person>";
270/// let person: Person = facet_xml::from_slice(xml_bytes).unwrap();
271/// assert_eq!(person.name, "Alice");
272/// assert_eq!(person.id, 42);
273/// ```
274pub fn from_slice<'input, 'facet, T>(xml: &'input [u8]) -> Result<T>
275where
276    T: Facet<'facet>,
277    'input: 'facet,
278{
279    from_slice_with_options(xml, &DeserializeOptions::default())
280}
281
282/// Deserialize an XML byte slice into a value of type `T` with custom options.
283///
284/// This is a convenience wrapper around [`from_str_with_options`] that first validates
285/// that the input is valid UTF-8.
286///
287/// # Example
288///
289/// ```
290/// use facet::Facet;
291/// use facet_xml::{self as xml, DeserializeOptions};
292///
293/// #[derive(Facet, Debug, PartialEq)]
294/// struct Person {
295///     #[facet(xml::attribute)]
296///     name: String,
297/// }
298///
299/// let options = DeserializeOptions::default().deny_unknown_fields(true);
300/// let xml_bytes = b"<Person name=\"Alice\"/>";
301/// let person: Person = xml::from_slice_with_options(xml_bytes, &options).unwrap();
302/// assert_eq!(person.name, "Alice");
303/// ```
304pub fn from_slice_with_options<'input, 'facet, T>(
305    xml: &'input [u8],
306    options: &DeserializeOptions,
307) -> Result<T>
308where
309    T: Facet<'facet>,
310    'input: 'facet,
311{
312    let xml_str = std::str::from_utf8(xml)
313        .map_err(|e| XmlError::new(XmlErrorKind::InvalidUtf8(e.to_string())))?;
314    from_str_with_options(xml_str, options)
315}
316
317/// Deserialize an XML byte slice into an owned type.
318///
319/// This variant does not require the input to outlive the result, making it
320/// suitable for deserializing from temporary buffers (e.g., HTTP request bodies).
321///
322/// Types containing `&str` fields cannot be deserialized with this function;
323/// use `String` or `Cow<str>` instead.
324///
325/// # Example
326///
327/// ```
328/// use facet::Facet;
329/// use facet_xml as xml;
330///
331/// #[derive(Facet, Debug, PartialEq)]
332/// struct Person {
333///     #[facet(xml::attribute)]
334///     id: u32,
335///     #[facet(xml::element)]
336///     name: String,
337/// }
338///
339/// let xml_bytes = b"<Person id=\"42\"><name>Alice</name></Person>";
340/// let person: Person = xml::from_slice_owned(xml_bytes).unwrap();
341/// assert_eq!(person.name, "Alice");
342/// assert_eq!(person.id, 42);
343/// ```
344pub fn from_slice_owned<T: Facet<'static>>(xml: &[u8]) -> Result<T> {
345    let xml_str = std::str::from_utf8(xml)
346        .map_err(|e| XmlError::new(XmlErrorKind::InvalidUtf8(e.to_string())))?;
347
348    log::trace!(
349        "from_slice_owned: parsing XML for type {}",
350        core::any::type_name::<T>()
351    );
352
353    let options = DeserializeOptions::default();
354    let mut deserializer = XmlDeserializer::new(xml_str, options)?;
355    let partial = Partial::alloc::<T>()?;
356
357    let partial = deserializer.deserialize_document(partial)?;
358
359    let result = partial
360        .build()
361        .map_err(|e| XmlError::new(XmlErrorKind::Reflect(e)).with_source(xml_str))?
362        .materialize()
363        .map_err(|e| XmlError::new(XmlErrorKind::Reflect(e)).with_source(xml_str))?;
364
365    Ok(result)
366}
367
368// ============================================================================
369// Extension trait for XML-specific field attributes
370// ============================================================================
371
372/// Extension trait for Field to check XML-specific attributes.
373pub(crate) trait XmlFieldExt {
374    /// Returns true if this field is an element field.
375    fn is_xml_element(&self) -> bool;
376    /// Returns true if this field is an elements (list) field.
377    fn is_xml_elements(&self) -> bool;
378    /// Returns true if this field is an attribute field.
379    fn is_xml_attribute(&self) -> bool;
380    /// Returns true if this field is a text field.
381    fn is_xml_text(&self) -> bool;
382    /// Returns true if this field stores the element name.
383    #[allow(dead_code)]
384    fn is_xml_element_name(&self) -> bool;
385    /// Returns the expected XML namespace URI for this field, if specified.
386    ///
387    /// Returns `Some(ns)` if the field has `#[facet(xml::ns = "...")]`,
388    /// or `None` if no namespace constraint is specified (matches any namespace).
389    fn xml_ns(&self) -> Option<&'static str>;
390}
391
392impl XmlFieldExt for Field {
393    fn is_xml_element(&self) -> bool {
394        self.is_child() || self.has_attr(Some("xml"), "element")
395    }
396
397    fn is_xml_elements(&self) -> bool {
398        self.has_attr(Some("xml"), "elements")
399    }
400
401    fn is_xml_attribute(&self) -> bool {
402        self.has_attr(Some("xml"), "attribute")
403    }
404
405    fn is_xml_text(&self) -> bool {
406        self.has_attr(Some("xml"), "text")
407    }
408
409    fn is_xml_element_name(&self) -> bool {
410        self.has_attr(Some("xml"), "element_name")
411    }
412
413    fn xml_ns(&self) -> Option<&'static str> {
414        self.get_attr(Some("xml"), "ns")
415            .and_then(|attr| attr.get_as::<&str>().copied())
416    }
417}
418
419/// Extension trait for Shape to check XML-specific container attributes.
420pub(crate) trait XmlShapeExt {
421    /// Returns the default XML namespace URI for all fields in this container.
422    ///
423    /// Returns `Some(ns)` if the shape has `#[facet(xml::ns_all = "...")]`,
424    /// or `None` if no default namespace is specified.
425    fn xml_ns_all(&self) -> Option<&'static str>;
426}
427
428impl XmlShapeExt for facet_core::Shape {
429    fn xml_ns_all(&self) -> Option<&'static str> {
430        self.attributes
431            .iter()
432            .find(|attr| attr.ns == Some("xml") && attr.key == "ns_all")
433            .and_then(|attr| attr.get_as::<&str>().copied())
434    }
435}
436
437// ============================================================================
438// Qualified Name (namespace + local name)
439// ============================================================================
440
441/// A qualified XML name with optional namespace URI.
442///
443/// In XML, elements and attributes can be in a namespace. The namespace is
444/// identified by a URI, not the prefix used in the document. For example,
445/// `android:label` and `a:label` are the same if both prefixes resolve to
446/// the same namespace URI.
447#[derive(Debug, Clone, PartialEq, Eq)]
448struct QName {
449    /// The namespace URI, or `None` for "no namespace".
450    ///
451    /// - Elements without a prefix and no default `xmlns` are in no namespace.
452    /// - Attributes without a prefix are always in no namespace (even with default xmlns).
453    /// - Elements/attributes with a prefix have their namespace resolved via xmlns declarations.
454    namespace: Option<String>,
455    /// The local name (without prefix).
456    local_name: String,
457}
458
459impl QName {
460    /// Create a qualified name with no namespace.
461    fn local(name: impl Into<String>) -> Self {
462        Self {
463            namespace: None,
464            local_name: name.into(),
465        }
466    }
467
468    /// Create a qualified name with a namespace.
469    fn with_ns(namespace: impl Into<String>, local_name: impl Into<String>) -> Self {
470        Self {
471            namespace: Some(namespace.into()),
472            local_name: local_name.into(),
473        }
474    }
475
476    /// Check if this name matches a local name with an optional expected namespace.
477    ///
478    /// If `expected_ns` is `None`, matches any name with the given local name.
479    /// If `expected_ns` is `Some(ns)`, only matches if both local name and namespace match.
480    fn matches(&self, local_name: &str, expected_ns: Option<&str>) -> bool {
481        if self.local_name != local_name {
482            return false;
483        }
484        match expected_ns {
485            None => true, // No namespace constraint - match any namespace (or none)
486            Some(ns) => self.namespace.as_deref() == Some(ns),
487        }
488    }
489
490    /// Check if this name matches exactly (same local name and same namespace presence).
491    ///
492    /// Unlike `matches()`, this requires the namespace to match exactly:
493    /// - expected_ns: None means the element must be in "no namespace"
494    /// - expected_ns: Some(ns) means the element must be in that specific namespace
495    #[allow(dead_code)]
496    fn matches_exact(&self, local_name: &str, expected_ns: Option<&str>) -> bool {
497        self.local_name == local_name && self.namespace.as_deref() == expected_ns
498    }
499}
500
501impl std::fmt::Display for QName {
502    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
503        match &self.namespace {
504            Some(ns) => write!(f, "{{{}}}{}", ns, self.local_name),
505            None => write!(f, "{}", self.local_name),
506        }
507    }
508}
509
510/// Compare QName with str by local name only (for backward compatibility).
511impl PartialEq<str> for QName {
512    fn eq(&self, other: &str) -> bool {
513        self.local_name == other
514    }
515}
516
517impl PartialEq<&str> for QName {
518    fn eq(&self, other: &&str) -> bool {
519        self.local_name == *other
520    }
521}
522
523impl PartialEq<QName> for str {
524    fn eq(&self, other: &QName) -> bool {
525        self == other.local_name
526    }
527}
528
529impl PartialEq<QName> for &str {
530    fn eq(&self, other: &QName) -> bool {
531        *self == other.local_name
532    }
533}
534
535// ============================================================================
536// Entity Resolution
537// ============================================================================
538
539/// Resolve a general entity reference to its character value.
540/// Handles both named entities (lt, gt, amp, etc.) and numeric entities (&#10;, &#x09;, etc.)
541fn resolve_entity(raw: &str) -> Result<String> {
542    // Try named entity first (e.g., "lt" -> "<")
543    if let Some(resolved) = resolve_xml_entity(raw) {
544        return Ok(resolved.into());
545    }
546
547    // Try numeric entity (e.g., "#10" -> "\n", "#x09" -> "\t")
548    if let Some(rest) = raw.strip_prefix('#') {
549        let code = if let Some(hex) = rest.strip_prefix('x').or_else(|| rest.strip_prefix('X')) {
550            // Hexadecimal numeric entity
551            u32::from_str_radix(hex, 16).map_err(|_| {
552                XmlError::new(XmlErrorKind::Parse(format!(
553                    "Invalid hex numeric entity: #{}",
554                    rest
555                )))
556            })?
557        } else {
558            // Decimal numeric entity
559            rest.parse::<u32>().map_err(|_| {
560                XmlError::new(XmlErrorKind::Parse(format!(
561                    "Invalid decimal numeric entity: #{}",
562                    rest
563                )))
564            })?
565        };
566
567        let ch = char::from_u32(code).ok_or_else(|| {
568            XmlError::new(XmlErrorKind::Parse(format!(
569                "Invalid Unicode code point: {}",
570                code
571            )))
572        })?;
573        return Ok(ch.to_string());
574    }
575
576    // Unknown entity - return as-is with & and ;
577    Ok(format!("&{};", raw))
578}
579
580// ============================================================================
581// Event wrapper with owned strings
582// ============================================================================
583
584/// An XML event with owned string data and span information.
585#[derive(Debug, Clone)]
586enum OwnedEvent {
587    /// Start of an element with qualified name and attributes
588    Start {
589        name: QName,
590        attributes: Vec<(QName, String)>,
591    },
592    /// End of an element
593    End { name: QName },
594    /// Empty element (self-closing)
595    Empty {
596        name: QName,
597        attributes: Vec<(QName, String)>,
598    },
599    /// Text content
600    Text { content: String },
601    /// CDATA content
602    CData { content: String },
603    /// End of file
604    Eof,
605}
606
607#[derive(Debug, Clone)]
608struct SpannedEvent {
609    event: OwnedEvent,
610    /// Byte offset in the original input where this event starts.
611    offset: usize,
612    /// Length of the event in bytes.
613    len: usize,
614}
615
616impl SpannedEvent {
617    fn span(&self) -> SourceSpan {
618        SourceSpan::from((self.offset, self.len))
619    }
620}
621
622// ============================================================================
623// Event Collector
624// ============================================================================
625
626/// Collects all events from the parser upfront, resolving namespaces.
627struct EventCollector<'input> {
628    reader: NsReader<&'input [u8]>,
629    input: &'input str,
630}
631
632impl<'input> EventCollector<'input> {
633    fn new(input: &'input str) -> Self {
634        let mut reader = NsReader::from_str(input);
635        // Don't use trim_text(true) - it drops whitespace-only text events
636        // which breaks entity handling (spaces between entities are lost).
637        // We handle whitespace filtering at the consumption level instead.
638        reader.config_mut().trim_text(false);
639        Self { reader, input }
640    }
641
642    /// Convert a ResolveResult to an optional namespace string.
643    fn resolve_ns(resolve: ResolveResult<'_>) -> Option<String> {
644        match resolve {
645            ResolveResult::Bound(ns) => Some(String::from_utf8_lossy(ns.as_ref()).into_owned()),
646            ResolveResult::Unbound => None,
647            ResolveResult::Unknown(prefix) => {
648                // Unknown prefix - treat as unbound but log a warning
649                log::warn!(
650                    "Unknown namespace prefix: {}",
651                    String::from_utf8_lossy(&prefix)
652                );
653                None
654            }
655        }
656    }
657
658    fn collect_all(mut self) -> Result<Vec<SpannedEvent>> {
659        let mut events = Vec::new();
660        let mut buf = Vec::new();
661
662        loop {
663            let offset = self.reader.buffer_position() as usize;
664            let (resolve, event) = self
665                .reader
666                .read_resolved_event_into(&mut buf)
667                .map_err(|e| {
668                    XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
669                })?;
670
671            let (owned, len) = match event {
672                Event::Start(ref e) => {
673                    // Convert namespace to owned before calling methods on self
674                    let ns = Self::resolve_ns(resolve);
675                    let local = String::from_utf8_lossy(e.local_name().as_ref()).into_owned();
676                    let name = match ns {
677                        Some(uri) => QName::with_ns(uri, local),
678                        None => QName::local(local),
679                    };
680                    let attributes = self.collect_attributes(e)?;
681                    let len = self.reader.buffer_position() as usize - offset;
682                    (OwnedEvent::Start { name, attributes }, len)
683                }
684                Event::End(ref e) => {
685                    // For End events, we need to resolve the element name
686                    let (resolve, _) = self.reader.resolve_element(e.name());
687                    let ns = Self::resolve_ns(resolve);
688                    let local = String::from_utf8_lossy(e.local_name().as_ref()).into_owned();
689                    let name = match ns {
690                        Some(uri) => QName::with_ns(uri, local),
691                        None => QName::local(local),
692                    };
693                    let len = self.reader.buffer_position() as usize - offset;
694                    (OwnedEvent::End { name }, len)
695                }
696                Event::Empty(ref e) => {
697                    // Convert namespace to owned before calling methods on self
698                    let ns = Self::resolve_ns(resolve);
699                    let local = String::from_utf8_lossy(e.local_name().as_ref()).into_owned();
700                    let name = match ns {
701                        Some(uri) => QName::with_ns(uri, local),
702                        None => QName::local(local),
703                    };
704                    let attributes = self.collect_attributes(e)?;
705                    let len = self.reader.buffer_position() as usize - offset;
706                    (OwnedEvent::Empty { name, attributes }, len)
707                }
708                Event::Text(e) => {
709                    let content = e.decode().map_err(|e| {
710                        XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
711                    })?;
712                    // Don't skip whitespace-only text at collection time.
713                    // It may be significant when adjacent to entity references.
714                    // Consumers filter whitespace as needed.
715                    let len = self.reader.buffer_position() as usize - offset;
716                    (
717                        OwnedEvent::Text {
718                            content: content.into_owned(),
719                        },
720                        len,
721                    )
722                }
723                Event::CData(e) => {
724                    let content = String::from_utf8_lossy(&e).into_owned();
725                    let len = self.reader.buffer_position() as usize - offset;
726                    (OwnedEvent::CData { content }, len)
727                }
728                Event::Eof => {
729                    events.push(SpannedEvent {
730                        event: OwnedEvent::Eof,
731                        offset,
732                        len: 0,
733                    });
734                    break;
735                }
736                Event::GeneralRef(e) => {
737                    // General entity references (e.g., &lt;, &gt;, &amp;, &#10;, etc.)
738                    // These are reported separately in quick-xml 0.38+ for text content.
739                    // Resolve the entity and emit as a Text event.
740                    let raw = e.decode().map_err(|e| {
741                        XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
742                    })?;
743                    let content = resolve_entity(&raw)?;
744                    let len = self.reader.buffer_position() as usize - offset;
745                    (OwnedEvent::Text { content }, len)
746                }
747                Event::Comment(_) | Event::Decl(_) | Event::PI(_) | Event::DocType(_) => {
748                    // Skip comments, declarations, processing instructions, doctypes
749                    buf.clear();
750                    continue;
751                }
752            };
753
754            log::trace!("XML event: {owned:?} at offset {offset}");
755            events.push(SpannedEvent {
756                event: owned,
757                offset,
758                len,
759            });
760            buf.clear();
761        }
762
763        Ok(events)
764    }
765
766    fn collect_attributes(&self, e: &BytesStart<'_>) -> Result<Vec<(QName, String)>> {
767        let mut attrs = Vec::new();
768        for attr in e.attributes() {
769            let attr = attr.map_err(|e| {
770                XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
771            })?;
772
773            // Ignore attributes reserved for XML namespace declarations
774            if is_xml_namespace_attribute(&attr.key) {
775                continue;
776            }
777
778            // Resolve attribute namespace
779            let (resolve, _) = self.reader.resolve_attribute(attr.key);
780            let ns = Self::resolve_ns(resolve);
781            let local = String::from_utf8_lossy(attr.key.local_name().as_ref()).into_owned();
782            let qname = match ns {
783                Some(uri) => QName::with_ns(uri, local),
784                None => QName::local(local),
785            };
786
787            let value = attr
788                .unescape_value()
789                .map_err(|e| {
790                    XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
791                })?
792                .into_owned();
793
794            attrs.push((qname, value));
795        }
796        Ok(attrs)
797    }
798}
799
800// ============================================================================
801// Deserializer
802// ============================================================================
803
804/// XML deserializer that processes events from a collected event stream.
805struct XmlDeserializer<'input> {
806    input: &'input str,
807    events: Vec<SpannedEvent>,
808    pos: usize,
809    options: DeserializeOptions,
810}
811
812impl<'input> XmlDeserializer<'input> {
813    /// Create a new deserializer by parsing the input and collecting all events.
814    fn new(input: &'input str, options: DeserializeOptions) -> Result<Self> {
815        let collector = EventCollector::new(input);
816        let events = collector.collect_all()?;
817
818        Ok(Self {
819            input,
820            events,
821            pos: 0,
822            options,
823        })
824    }
825
826    /// Create an error with source code attached for diagnostics.
827    fn err(&self, kind: impl Into<XmlErrorKind>) -> XmlError {
828        XmlError::new(kind).with_source(self.input.to_string())
829    }
830
831    /// Create an error with source code and span attached for diagnostics.
832    fn err_at(&self, kind: impl Into<XmlErrorKind>, span: impl Into<SourceSpan>) -> XmlError {
833        XmlError::new(kind)
834            .with_source(self.input.to_string())
835            .with_span(span)
836    }
837
838    /// Consume and return the current event (cloned to avoid borrow issues).
839    fn next(&mut self) -> Option<SpannedEvent> {
840        if self.pos < self.events.len() {
841            let event = self.events[self.pos].clone();
842            self.pos += 1;
843            Some(event)
844        } else {
845            None
846        }
847    }
848
849    /// Save current position for potential rewind.
850    #[allow(dead_code)]
851    fn save_position(&self) -> usize {
852        self.pos
853    }
854
855    /// Restore to a previously saved position.
856    #[allow(dead_code)]
857    fn restore_position(&mut self, pos: usize) {
858        self.pos = pos;
859    }
860
861    /// Deserialize the document starting from the root element.
862    fn deserialize_document<'facet>(
863        &mut self,
864        partial: Partial<'facet>,
865    ) -> Result<Partial<'facet>> {
866        // Expect a start or empty element
867        let Some(event) = self.next() else {
868            return Err(self.err(XmlErrorKind::UnexpectedEof));
869        };
870
871        let span = event.span();
872
873        match event.event {
874            OwnedEvent::Start { name, attributes } => {
875                self.deserialize_element(partial, &name, &attributes, span, false)
876            }
877            OwnedEvent::Empty { name, attributes } => {
878                self.deserialize_element(partial, &name, &attributes, span, true)
879            }
880            other => Err(self.err(XmlErrorKind::UnexpectedEvent(format!(
881                "expected start element, got {other:?}"
882            )))),
883        }
884    }
885
886    /// Deserialize an element into a partial value.
887    fn deserialize_element<'facet>(
888        &mut self,
889        partial: Partial<'facet>,
890        element_name: &QName,
891        attributes: &[(QName, String)],
892        span: SourceSpan,
893        is_empty: bool,
894    ) -> Result<Partial<'facet>> {
895        let mut partial = partial;
896        let shape = partial.shape();
897
898        log::trace!(
899            "deserialize_element: {:?} into shape {:?}",
900            element_name,
901            shape.ty
902        );
903
904        // Check Def first for scalars (String, etc.)
905        if matches!(&shape.def, Def::Scalar) {
906            // For scalar types, we expect text content
907            if is_empty {
908                // Empty element for a string means empty string
909                if shape.is_type::<String>() {
910                    partial = partial.set(String::new())?;
911                    return Ok(partial);
912                }
913                return Err(self.err_at(
914                    XmlErrorKind::InvalidValueForShape(
915                        "expected text content for scalar type".into(),
916                    ),
917                    span,
918                ));
919            }
920
921            // Get text content
922            let text = self.read_text_until_end(element_name)?;
923            partial = self.set_scalar_value(partial, &text)?;
924            return Ok(partial);
925        }
926
927        // Priority 1: Check for builder_shape (immutable collections like Bytes -> BytesMut)
928        if shape.builder_shape.is_some() {
929            partial = partial.begin_inner()?;
930            partial =
931                self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
932            partial = partial.end()?;
933            return Ok(partial);
934        }
935
936        // Handle Vec<u8> as base64
937        if let Def::List(list_def) = &shape.def
938            && list_def.t().is_type::<u8>()
939        {
940            if is_empty {
941                // Empty element = empty bytes
942                partial = partial.begin_list()?;
943                // Empty list, nothing to add
944                return Ok(partial);
945            }
946            let text = self.read_text_until_end(element_name)?;
947            let bytes = BASE64_STANDARD
948                .decode(text.trim())
949                .map_err(|e| self.err_at(XmlErrorKind::Base64Decode(e.to_string()), span))?;
950            partial = partial.begin_list()?;
951            for byte in bytes {
952                partial = partial.begin_list_item()?;
953                partial = partial.set(byte)?;
954                partial = partial.end()?; // end list item
955            }
956            return Ok(partial);
957        }
958
959        // Handle [u8; N] as base64
960        if let Def::Array(arr_def) = &shape.def
961            && arr_def.t().is_type::<u8>()
962        {
963            if is_empty {
964                return Err(self.err_at(
965                    XmlErrorKind::InvalidValueForShape("empty element for byte array".into()),
966                    span,
967                ));
968            }
969            let text = self.read_text_until_end(element_name)?;
970            let bytes = BASE64_STANDARD
971                .decode(text.trim())
972                .map_err(|e| self.err_at(XmlErrorKind::Base64Decode(e.to_string()), span))?;
973            if bytes.len() != arr_def.n {
974                return Err(self.err_at(
975                    XmlErrorKind::InvalidValueForShape(format!(
976                        "base64 decoded {} bytes, expected {}",
977                        bytes.len(),
978                        arr_def.n
979                    )),
980                    span,
981                ));
982            }
983            for (idx, byte) in bytes.into_iter().enumerate() {
984                partial = partial.begin_nth_field(idx)?;
985                partial = partial.set(byte)?;
986                partial = partial.end()?;
987            }
988            return Ok(partial);
989        }
990
991        // Handle fixed arrays (non-byte)
992        if let Def::Array(arr_def) = &shape.def {
993            if is_empty {
994                return Err(self.err_at(
995                    XmlErrorKind::InvalidValueForShape("empty element for array".into()),
996                    span,
997                ));
998            }
999            let array_len = arr_def.n;
1000            return self.deserialize_array_content(partial, array_len, element_name);
1001        }
1002
1003        // Handle sets
1004        if matches!(&shape.def, Def::Set(_)) {
1005            if is_empty {
1006                partial = partial.begin_set()?;
1007                // Empty set - nothing to do
1008                return Ok(partial);
1009            }
1010            return self.deserialize_set_content(partial, element_name);
1011        }
1012
1013        // Handle maps
1014        if matches!(&shape.def, Def::Map(_)) {
1015            if is_empty {
1016                partial = partial.begin_map()?;
1017                // Empty map - nothing to do
1018                return Ok(partial);
1019            }
1020            return self.deserialize_map_content(partial, element_name);
1021        }
1022
1023        // Check for .inner (transparent wrappers like NonZero)
1024        // Collections (List/Map/Set/Array) have .inner for variance but shouldn't use this path
1025        if shape.inner.is_some()
1026            && !matches!(
1027                &shape.def,
1028                Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
1029            )
1030        {
1031            partial = partial.begin_inner()?;
1032            partial =
1033                self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
1034            partial = partial.end()?;
1035            return Ok(partial);
1036        }
1037
1038        // Handle different shapes
1039        match &shape.ty {
1040            Type::User(UserType::Struct(struct_def)) => {
1041                // Get fields
1042                let fields = struct_def.fields;
1043                // Deny unknown if either the option or the attribute is set
1044                let deny_unknown =
1045                    self.options.deny_unknown_fields || shape.has_deny_unknown_fields_attr();
1046
1047                match struct_def.kind {
1048                    StructKind::Unit => {
1049                        // Unit struct - nothing to deserialize, just skip content
1050                        if !is_empty {
1051                            self.skip_element(element_name)?;
1052                        }
1053                        return Ok(partial);
1054                    }
1055                    StructKind::Tuple | StructKind::TupleStruct => {
1056                        // Tuple struct - deserialize fields by position
1057                        if is_empty {
1058                            // Set defaults for all fields
1059                            partial = self.set_defaults_for_unset_fields(partial, fields)?;
1060                            return Ok(partial);
1061                        }
1062
1063                        // Deserialize tuple fields from child elements
1064                        partial = self.deserialize_tuple_content(partial, fields, element_name)?;
1065
1066                        // Set defaults for any unset fields
1067                        partial = self.set_defaults_for_unset_fields(partial, fields)?;
1068                        return Ok(partial);
1069                    }
1070                    StructKind::Struct => {
1071                        // Check if this struct has flattened fields - if so, use the solver
1072                        if Self::has_flatten_fields(struct_def) {
1073                            return self.deserialize_struct_with_flatten(
1074                                partial,
1075                                struct_def,
1076                                element_name,
1077                                attributes,
1078                                span,
1079                                is_empty,
1080                            );
1081                        }
1082                        // Normal named struct - fall through to standard handling
1083                    }
1084                }
1085
1086                let missing =
1087                    fields_missing_xml_annotations(fields, XmlAnnotationPhase::Deserialize);
1088                if !missing.is_empty() {
1089                    let field_info = missing
1090                        .into_iter()
1091                        .map(|field| (field.name, field.shape().type_identifier))
1092                        .collect();
1093                    return Err(self.err(XmlErrorKind::MissingXmlAnnotations {
1094                        type_name: shape.type_identifier,
1095                        phase: MissingAnnotationPhase::Deserialize,
1096                        fields: field_info,
1097                    }));
1098                }
1099
1100                // First, deserialize attributes
1101                partial =
1102                    self.deserialize_attributes(partial, fields, attributes, deny_unknown, span)?;
1103
1104                // If empty element, we're done with content
1105                if is_empty {
1106                    // Set defaults for missing fields
1107                    partial = self.set_defaults_for_unset_fields(partial, fields)?;
1108                    return Ok(partial);
1109                }
1110
1111                // Deserialize child elements and text content
1112                partial =
1113                    self.deserialize_element_content(partial, fields, element_name, deny_unknown)?;
1114
1115                // Set defaults for any unset fields
1116                partial = self.set_defaults_for_unset_fields(partial, fields)?;
1117
1118                Ok(partial)
1119            }
1120            Type::User(UserType::Enum(enum_def)) => {
1121                // Determine enum tagging strategy
1122                let is_untagged = shape.is_untagged();
1123                let tag_attr = shape.get_tag_attr();
1124                let content_attr = shape.get_content_attr();
1125
1126                if is_untagged {
1127                    // Untagged: try each variant until one works
1128                    return self.deserialize_untagged_enum(
1129                        partial,
1130                        enum_def,
1131                        element_name,
1132                        attributes,
1133                        span,
1134                        is_empty,
1135                    );
1136                } else if let Some(tag) = tag_attr {
1137                    // Get variant name from attribute
1138                    let variant_name = attributes
1139                        .iter()
1140                        .find(|(k, _)| k == tag)
1141                        .map(|(_, v)| v.clone())
1142                        .ok_or_else(|| {
1143                            self.err_at(XmlErrorKind::MissingAttribute(tag.to_string()), span)
1144                        })?;
1145
1146                    // Find the variant by name
1147                    let variant = enum_def
1148                        .variants
1149                        .iter()
1150                        .find(|v| v.name == variant_name)
1151                        .ok_or_else(|| {
1152                            self.err_at(
1153                                XmlErrorKind::NoMatchingElement(variant_name.to_string()),
1154                                span,
1155                            )
1156                        })?;
1157
1158                    // Select the variant
1159                    partial = partial.select_variant_named(&variant_name)?;
1160                    let variant_fields = variant.data.fields;
1161
1162                    if let Some(content) = content_attr {
1163                        // Adjacently tagged: <Element tag="Variant"><content>...</content></Element>
1164                        if is_empty {
1165                            // No content element for empty element
1166                            partial =
1167                                self.set_defaults_for_unset_fields(partial, variant_fields)?;
1168                        } else {
1169                            // Find the content element
1170                            partial = self.deserialize_adjacently_tagged_content(
1171                                partial,
1172                                variant,
1173                                content,
1174                                element_name,
1175                            )?;
1176                        }
1177                    } else {
1178                        // Internally tagged: <Element tag="Variant">...fields...</Element>
1179                        // Filter out the tag attribute
1180                        let other_attrs: Vec<_> = attributes
1181                            .iter()
1182                            .filter(|(k, _)| k != tag)
1183                            .cloned()
1184                            .collect();
1185
1186                        match variant.data.kind {
1187                            StructKind::Unit => {
1188                                // Unit variant - nothing to deserialize
1189                                if !is_empty {
1190                                    self.skip_element(element_name)?;
1191                                }
1192                            }
1193                            StructKind::Tuple | StructKind::TupleStruct => {
1194                                // Tuple variant - deserialize fields by position
1195                                if !is_empty {
1196                                    partial = self.deserialize_tuple_content(
1197                                        partial,
1198                                        variant_fields,
1199                                        element_name,
1200                                    )?;
1201                                }
1202                                partial =
1203                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
1204                            }
1205                            StructKind::Struct => {
1206                                // Struct variant - deserialize as struct
1207                                partial = self.deserialize_attributes(
1208                                    partial,
1209                                    variant_fields,
1210                                    &other_attrs,
1211                                    false,
1212                                    span,
1213                                )?;
1214                                if !is_empty {
1215                                    partial = self.deserialize_element_content(
1216                                        partial,
1217                                        variant_fields,
1218                                        element_name,
1219                                        false,
1220                                    )?;
1221                                }
1222                                partial =
1223                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
1224                            }
1225                        }
1226                    }
1227
1228                    return Ok(partial);
1229                }
1230
1231                // Externally tagged (default) - two modes:
1232                // 1. Element name IS a variant name: <VariantName attr="...">...</VariantName>
1233                // 2. Element is a wrapper: <Wrapper><VariantName>...</VariantName></Wrapper>
1234
1235                // Check if element name matches a variant's display name
1236                if let Some(variant) = enum_def
1237                    .variants
1238                    .iter()
1239                    .find(|v| get_variant_display_name(v) == element_name)
1240                {
1241                    // Mode 1: The element itself is the variant
1242                    // Use the original variant name for selection
1243                    partial = partial.select_variant_named(variant.name)?;
1244                    let variant_fields = variant.data.fields;
1245
1246                    match variant.data.kind {
1247                        StructKind::Unit => {
1248                            // Unit variant - nothing to deserialize
1249                            if !is_empty {
1250                                self.skip_element(element_name)?;
1251                            }
1252                        }
1253                        StructKind::Tuple | StructKind::TupleStruct => {
1254                            // Tuple variant - check for newtype pattern
1255                            if variant_fields.len() == 1 {
1256                                // Newtype variant - deserialize inner value from current element
1257                                partial = partial.begin_nth_field(0)?;
1258                                partial = self.deserialize_element(
1259                                    partial,
1260                                    element_name,
1261                                    attributes,
1262                                    span,
1263                                    is_empty,
1264                                )?;
1265                                partial = partial.end()?;
1266                            } else if !is_empty {
1267                                // Multi-field tuple - deserialize from child elements
1268                                partial = self.deserialize_tuple_content(
1269                                    partial,
1270                                    variant_fields,
1271                                    element_name,
1272                                )?;
1273                                partial =
1274                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
1275                            } else {
1276                                partial =
1277                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
1278                            }
1279                        }
1280                        StructKind::Struct => {
1281                            // Struct variant - deserialize attributes and content
1282                            partial = self.deserialize_attributes(
1283                                partial,
1284                                variant_fields,
1285                                attributes,
1286                                false,
1287                                span,
1288                            )?;
1289                            if !is_empty {
1290                                partial = self.deserialize_element_content(
1291                                    partial,
1292                                    variant_fields,
1293                                    element_name,
1294                                    false,
1295                                )?;
1296                            }
1297                            partial =
1298                                self.set_defaults_for_unset_fields(partial, variant_fields)?;
1299                        }
1300                    }
1301
1302                    return Ok(partial);
1303                }
1304
1305                // Mode 2: Element is a wrapper containing the variant element
1306                if is_empty {
1307                    return Err(self.err_at(
1308                        XmlErrorKind::InvalidValueForShape(
1309                            "empty element for externally tagged enum".into(),
1310                        ),
1311                        span,
1312                    ));
1313                }
1314
1315                // Read the variant element
1316                let variant_event = loop {
1317                    let Some(event) = self.next() else {
1318                        return Err(self.err(XmlErrorKind::UnexpectedEof));
1319                    };
1320
1321                    match &event.event {
1322                        OwnedEvent::Text { content } if content.trim().is_empty() => {
1323                            // Skip whitespace
1324                            continue;
1325                        }
1326                        OwnedEvent::Start { .. } | OwnedEvent::Empty { .. } => {
1327                            break event;
1328                        }
1329                        _ => {
1330                            return Err(self.err_at(
1331                                XmlErrorKind::UnexpectedEvent(format!(
1332                                    "expected variant element, got {:?}",
1333                                    event.event
1334                                )),
1335                                event.span(),
1336                            ));
1337                        }
1338                    }
1339                };
1340
1341                let variant_span = variant_event.span();
1342                let (variant_name, variant_attrs, variant_is_empty) = match &variant_event.event {
1343                    OwnedEvent::Start { name, attributes } => {
1344                        (name.clone(), attributes.clone(), false)
1345                    }
1346                    OwnedEvent::Empty { name, attributes } => {
1347                        (name.clone(), attributes.clone(), true)
1348                    }
1349                    _ => unreachable!(),
1350                };
1351
1352                // Find the variant by display name (considering rename)
1353                let variant = enum_def
1354                    .variants
1355                    .iter()
1356                    .find(|v| get_variant_display_name(v) == variant_name)
1357                    .ok_or_else(|| {
1358                        self.err_at(
1359                            XmlErrorKind::NoMatchingElement(variant_name.to_string()),
1360                            variant_span,
1361                        )
1362                    })?;
1363
1364                // Select the variant using its original name
1365                partial = partial.select_variant_named(variant.name)?;
1366
1367                let variant_fields = variant.data.fields;
1368
1369                match variant.data.kind {
1370                    StructKind::Unit => {
1371                        // Unit variant - nothing to deserialize
1372                        if !variant_is_empty {
1373                            self.skip_element(&variant_name)?;
1374                        }
1375                    }
1376                    StructKind::Tuple | StructKind::TupleStruct => {
1377                        // Tuple variant - deserialize fields by position
1378                        if !variant_is_empty {
1379                            partial = self.deserialize_tuple_content(
1380                                partial,
1381                                variant_fields,
1382                                &variant_name,
1383                            )?;
1384                        }
1385                        partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
1386                    }
1387                    StructKind::Struct => {
1388                        // Struct variant - deserialize as struct
1389                        partial = self.deserialize_attributes(
1390                            partial,
1391                            variant_fields,
1392                            &variant_attrs,
1393                            false,
1394                            variant_span,
1395                        )?;
1396                        if !variant_is_empty {
1397                            partial = self.deserialize_element_content(
1398                                partial,
1399                                variant_fields,
1400                                &variant_name,
1401                                false,
1402                            )?;
1403                        }
1404                        partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
1405                    }
1406                }
1407
1408                // Skip to the end of the wrapper element
1409                loop {
1410                    let Some(event) = self.next() else {
1411                        return Err(self.err(XmlErrorKind::UnexpectedEof));
1412                    };
1413
1414                    match &event.event {
1415                        OwnedEvent::End { name } if name == element_name => {
1416                            break;
1417                        }
1418                        OwnedEvent::Text { content } if content.trim().is_empty() => {
1419                            // Skip whitespace
1420                            continue;
1421                        }
1422                        _ => {
1423                            return Err(self.err_at(
1424                                XmlErrorKind::UnexpectedEvent(format!(
1425                                    "expected end of enum wrapper, got {:?}",
1426                                    event.event
1427                                )),
1428                                event.span(),
1429                            ));
1430                        }
1431                    }
1432                }
1433
1434                Ok(partial)
1435            }
1436            _ => Err(self.err_at(
1437                XmlErrorKind::UnsupportedShape(format!("cannot deserialize into {:?}", shape.ty)),
1438                span,
1439            )),
1440        }
1441    }
1442
1443    /// Deserialize XML attributes into struct fields.
1444    fn deserialize_attributes<'facet>(
1445        &mut self,
1446        partial: Partial<'facet>,
1447        fields: &[Field],
1448        attributes: &[(QName, String)],
1449        deny_unknown: bool,
1450        element_span: SourceSpan,
1451    ) -> Result<Partial<'facet>> {
1452        let mut partial = partial;
1453
1454        for (attr_name, attr_value) in attributes {
1455            // Find the field that matches this attribute.
1456            // Uses namespace-aware matching:
1457            // - If field has xml::ns, it must match exactly
1458            // - Otherwise, match any namespace (including "no namespace")
1459            //
1460            // NOTE: Unlike elements, attributes do NOT inherit the default namespace (ns_all).
1461            // In XML, unprefixed attributes are always in "no namespace", even when a default
1462            // xmlns is declared. Only prefixed attributes (e.g., foo:bar) have a namespace.
1463            // See: https://www.w3.org/TR/xml-names/#defaulting
1464            let field_match = fields.iter().enumerate().find(|(_, f)| {
1465                f.is_xml_attribute() && attr_name.matches(local_name_of(f.name), f.xml_ns())
1466            });
1467
1468            if let Some((idx, field)) = field_match {
1469                log::trace!(
1470                    "deserialize attribute {} into field {}",
1471                    attr_name,
1472                    field.name
1473                );
1474
1475                partial = partial.begin_nth_field(idx)?;
1476
1477                // Check if field has custom deserialization - must check BEFORE navigating
1478                // into Option/Spanned wrappers, because begin_custom_deserialization needs
1479                // the field context (parent_field()) to access proxy_shape().
1480                let has_custom_deser = field.proxy_convert_in_fn().is_some();
1481                if has_custom_deser {
1482                    // When using proxy, the proxy type handles the full conversion including
1483                    // any Option/Spanned wrappers, so we deserialize directly into the proxy.
1484                    partial = partial.begin_custom_deserialization()?;
1485                    partial = self.set_scalar_value(partial, attr_value)?;
1486                    partial = partial.end()?; // end custom deserialization
1487                } else {
1488                    // No proxy - handle Option<T> and Spanned<T> wrappers manually
1489                    let is_option = matches!(&partial.shape().def, Def::Option(_));
1490                    if is_option {
1491                        partial = partial.begin_some()?;
1492                    }
1493
1494                    // Handle Spanned<T>
1495                    if is_spanned_shape(partial.shape()) {
1496                        partial = partial.begin_field("value")?;
1497                    }
1498
1499                    // Deserialize the value
1500                    partial = self.set_scalar_value(partial, attr_value)?;
1501
1502                    // End Spanned<T> if needed
1503                    if is_spanned_shape(field.shape()) {
1504                        partial = partial.end()?; // end value field
1505                    }
1506
1507                    // End Option<T> if needed
1508                    if is_option {
1509                        partial = partial.end()?; // end Some
1510                    }
1511                }
1512
1513                partial = partial.end()?; // end field
1514            } else if deny_unknown {
1515                // Unknown attribute when deny_unknown_fields is set
1516                let expected: Vec<&'static str> = fields
1517                    .iter()
1518                    .filter(|f| f.is_xml_attribute())
1519                    .map(|f| f.name)
1520                    .collect();
1521                return Err(self.err_at(
1522                    XmlErrorKind::UnknownAttribute {
1523                        attribute: attr_name.to_string(),
1524                        expected,
1525                    },
1526                    element_span,
1527                ));
1528            }
1529            // Otherwise ignore unknown attributes
1530        }
1531
1532        Ok(partial)
1533    }
1534
1535    /// Deserialize child elements and text content.
1536    fn deserialize_element_content<'facet>(
1537        &mut self,
1538        partial: Partial<'facet>,
1539        fields: &[Field],
1540        parent_element_name: &QName,
1541        deny_unknown: bool,
1542    ) -> Result<Partial<'facet>> {
1543        let mut partial = partial;
1544        let mut text_content = String::new();
1545
1546        // Track which element fields are lists (for xml::elements)
1547        let mut elements_field_started: Option<usize> = None;
1548
1549        loop {
1550            let Some(event) = self.next() else {
1551                return Err(self.err(XmlErrorKind::UnexpectedEof));
1552            };
1553
1554            let span = event.span();
1555
1556            match event.event {
1557                OwnedEvent::End { ref name } if name == parent_element_name => {
1558                    // End any open elements list field
1559                    // Note: begin_list() doesn't push a frame, so we only end the field
1560                    if elements_field_started.is_some() {
1561                        partial = partial.end()?; // end the elements field
1562                    }
1563
1564                    // Handle accumulated text content
1565                    if !text_content.is_empty() {
1566                        partial = self.set_text_field(partial, fields, &text_content)?;
1567                    }
1568
1569                    break;
1570                }
1571                OwnedEvent::Start { name, attributes } => {
1572                    partial = self.deserialize_child_element(
1573                        partial,
1574                        fields,
1575                        &name,
1576                        &attributes,
1577                        span,
1578                        false,
1579                        &mut elements_field_started,
1580                        deny_unknown,
1581                    )?;
1582                }
1583                OwnedEvent::Empty { name, attributes } => {
1584                    partial = self.deserialize_child_element(
1585                        partial,
1586                        fields,
1587                        &name,
1588                        &attributes,
1589                        span,
1590                        true,
1591                        &mut elements_field_started,
1592                        deny_unknown,
1593                    )?;
1594                }
1595                OwnedEvent::Text { content } | OwnedEvent::CData { content } => {
1596                    text_content.push_str(&content);
1597                }
1598                OwnedEvent::End { name } => {
1599                    // End tag for a different element - this shouldn't happen
1600                    return Err(self.err_at(
1601                        XmlErrorKind::UnexpectedEvent(format!(
1602                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
1603                        )),
1604                        span,
1605                    ));
1606                }
1607                OwnedEvent::Eof => {
1608                    return Err(self.err(XmlErrorKind::UnexpectedEof));
1609                }
1610            }
1611        }
1612
1613        Ok(partial)
1614    }
1615
1616    /// Deserialize tuple struct content - fields are numbered elements like `<_0>`, `<_1>`, etc.
1617    fn deserialize_tuple_content<'facet>(
1618        &mut self,
1619        partial: Partial<'facet>,
1620        fields: &[Field],
1621        parent_element_name: &QName,
1622    ) -> Result<Partial<'facet>> {
1623        let mut partial = partial;
1624        let mut field_idx = 0;
1625
1626        loop {
1627            let Some(event) = self.next() else {
1628                return Err(self.err(XmlErrorKind::UnexpectedEof));
1629            };
1630
1631            let span = event.span();
1632
1633            match event.event {
1634                OwnedEvent::End { ref name } if name == parent_element_name => {
1635                    break;
1636                }
1637                OwnedEvent::Start { name, attributes } => {
1638                    if field_idx >= fields.len() {
1639                        return Err(self.err_at(
1640                            XmlErrorKind::UnexpectedEvent(format!(
1641                                "too many elements for tuple struct (expected {})",
1642                                fields.len()
1643                            )),
1644                            span,
1645                        ));
1646                    }
1647
1648                    partial = partial.begin_nth_field(field_idx)?;
1649
1650                    // Handle Option<T>
1651                    let is_option = matches!(&partial.shape().def, Def::Option(_));
1652                    if is_option {
1653                        partial = partial.begin_some()?;
1654                    }
1655
1656                    partial = self.deserialize_element(partial, &name, &attributes, span, false)?;
1657                    if is_option {
1658                        partial = partial.end()?; // end Some
1659                    }
1660                    partial = partial.end()?; // end field
1661                    field_idx += 1;
1662                }
1663                OwnedEvent::Empty { name, attributes } => {
1664                    if field_idx >= fields.len() {
1665                        return Err(self.err_at(
1666                            XmlErrorKind::UnexpectedEvent(format!(
1667                                "too many elements for tuple struct (expected {})",
1668                                fields.len()
1669                            )),
1670                            span,
1671                        ));
1672                    }
1673
1674                    partial = partial.begin_nth_field(field_idx)?;
1675
1676                    // Handle Option<T>
1677                    let is_option = matches!(&partial.shape().def, Def::Option(_));
1678                    if is_option {
1679                        partial = partial.begin_some()?;
1680                    }
1681
1682                    partial = self.deserialize_element(partial, &name, &attributes, span, true)?;
1683                    if is_option {
1684                        partial = partial.end()?; // end Some
1685                    }
1686                    partial = partial.end()?; // end field
1687                    field_idx += 1;
1688                }
1689                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
1690                    // Ignore text content in tuple structs
1691                }
1692                OwnedEvent::End { name } => {
1693                    return Err(self.err_at(
1694                        XmlErrorKind::UnexpectedEvent(format!(
1695                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
1696                        )),
1697                        span,
1698                    ));
1699                }
1700                OwnedEvent::Eof => {
1701                    return Err(self.err(XmlErrorKind::UnexpectedEof));
1702                }
1703            }
1704        }
1705
1706        Ok(partial)
1707    }
1708
1709    /// Deserialize fixed array content - expects sequential child elements
1710    fn deserialize_array_content<'facet>(
1711        &mut self,
1712        partial: Partial<'facet>,
1713        array_len: usize,
1714        parent_element_name: &QName,
1715    ) -> Result<Partial<'facet>> {
1716        let mut partial = partial;
1717        let mut idx = 0;
1718
1719        loop {
1720            let Some(event) = self.next() else {
1721                return Err(self.err(XmlErrorKind::UnexpectedEof));
1722            };
1723
1724            let span = event.span();
1725
1726            match event.event {
1727                OwnedEvent::End { ref name } if name == parent_element_name => {
1728                    if idx < array_len {
1729                        return Err(self.err_at(
1730                            XmlErrorKind::InvalidValueForShape(format!(
1731                                "not enough elements for array (got {idx}, expected {array_len})"
1732                            )),
1733                            span,
1734                        ));
1735                    }
1736                    break;
1737                }
1738                OwnedEvent::Start { name, attributes } => {
1739                    if idx >= array_len {
1740                        return Err(self.err_at(
1741                            XmlErrorKind::InvalidValueForShape(format!(
1742                                "too many elements for array (expected {array_len})"
1743                            )),
1744                            span,
1745                        ));
1746                    }
1747                    partial = partial.begin_nth_field(idx)?;
1748                    partial = self.deserialize_element(partial, &name, &attributes, span, false)?;
1749                    partial = partial.end()?;
1750                    idx += 1;
1751                }
1752                OwnedEvent::Empty { name, attributes } => {
1753                    if idx >= array_len {
1754                        return Err(self.err_at(
1755                            XmlErrorKind::InvalidValueForShape(format!(
1756                                "too many elements for array (expected {array_len})"
1757                            )),
1758                            span,
1759                        ));
1760                    }
1761                    partial = partial.begin_nth_field(idx)?;
1762                    partial = self.deserialize_element(partial, &name, &attributes, span, true)?;
1763                    partial = partial.end()?;
1764                    idx += 1;
1765                }
1766                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
1767                    // Ignore whitespace between elements
1768                }
1769                OwnedEvent::End { name } => {
1770                    return Err(self.err_at(
1771                        XmlErrorKind::UnexpectedEvent(format!(
1772                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
1773                        )),
1774                        span,
1775                    ));
1776                }
1777                OwnedEvent::Eof => {
1778                    return Err(self.err(XmlErrorKind::UnexpectedEof));
1779                }
1780            }
1781        }
1782
1783        Ok(partial)
1784    }
1785
1786    /// Deserialize set content - each child element is a set item
1787    fn deserialize_set_content<'facet>(
1788        &mut self,
1789        partial: Partial<'facet>,
1790        parent_element_name: &QName,
1791    ) -> Result<Partial<'facet>> {
1792        let mut partial = partial;
1793        partial = partial.begin_set()?;
1794
1795        loop {
1796            let Some(event) = self.next() else {
1797                return Err(self.err(XmlErrorKind::UnexpectedEof));
1798            };
1799
1800            let span = event.span();
1801
1802            match event.event {
1803                OwnedEvent::End { ref name } if name == parent_element_name => {
1804                    break;
1805                }
1806                OwnedEvent::Start { name, attributes } => {
1807                    partial = partial.begin_set_item()?;
1808                    partial = self.deserialize_element(partial, &name, &attributes, span, false)?;
1809                    partial = partial.end()?; // end set item
1810                }
1811                OwnedEvent::Empty { name, attributes } => {
1812                    partial = partial.begin_set_item()?;
1813                    partial = self.deserialize_element(partial, &name, &attributes, span, true)?;
1814                    partial = partial.end()?; // end set item
1815                }
1816                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
1817                    // Ignore whitespace between elements
1818                }
1819                OwnedEvent::End { name } => {
1820                    return Err(self.err_at(
1821                        XmlErrorKind::UnexpectedEvent(format!(
1822                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
1823                        )),
1824                        span,
1825                    ));
1826                }
1827                OwnedEvent::Eof => {
1828                    return Err(self.err(XmlErrorKind::UnexpectedEof));
1829                }
1830            }
1831        }
1832
1833        Ok(partial)
1834    }
1835
1836    /// Deserialize map content - expects <entry key="...">value</entry> or similar structure
1837    fn deserialize_map_content<'facet>(
1838        &mut self,
1839        partial: Partial<'facet>,
1840        parent_element_name: &QName,
1841    ) -> Result<Partial<'facet>> {
1842        let mut partial = partial;
1843        partial = partial.begin_map()?;
1844
1845        loop {
1846            let Some(event) = self.next() else {
1847                return Err(self.err(XmlErrorKind::UnexpectedEof));
1848            };
1849
1850            let span = event.span();
1851
1852            match event.event {
1853                OwnedEvent::End { ref name } if name == parent_element_name => {
1854                    break;
1855                }
1856                OwnedEvent::Start { name, attributes } => {
1857                    // Map entry: element name is the key, content is the value
1858                    partial = partial.begin_key()?;
1859                    partial = partial.set(name.local_name.clone())?;
1860                    partial = partial.end()?; // end key
1861
1862                    partial = partial.begin_value()?;
1863                    // If there's a key attribute, use that as context; otherwise read content
1864                    partial = self.deserialize_map_entry_value(partial, &name, &attributes)?;
1865                    partial = partial.end()?; // end value
1866                }
1867                OwnedEvent::Empty { name, .. } => {
1868                    // Empty element as map entry - key is element name, value is default/empty
1869                    partial = partial.begin_key()?;
1870                    partial = partial.set(name.local_name.clone())?;
1871                    partial = partial.end()?; // end key
1872
1873                    partial = partial.begin_value()?;
1874                    // Set default value for the map value type
1875                    let value_shape = partial.shape();
1876                    if value_shape.is_type::<String>() {
1877                        partial = partial.set(String::new())?;
1878                    } else if value_shape.is_type::<bool>() {
1879                        partial = partial.set(true)?; // presence implies true
1880                    } else {
1881                        return Err(self.err_at(
1882                            XmlErrorKind::InvalidValueForShape(
1883                                "empty element for non-string/bool map value".into(),
1884                            ),
1885                            span,
1886                        ));
1887                    }
1888                    partial = partial.end()?; // end value
1889                }
1890                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
1891                    // Ignore whitespace between elements
1892                }
1893                OwnedEvent::End { name } => {
1894                    return Err(self.err_at(
1895                        XmlErrorKind::UnexpectedEvent(format!(
1896                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
1897                        )),
1898                        span,
1899                    ));
1900                }
1901                OwnedEvent::Eof => {
1902                    return Err(self.err(XmlErrorKind::UnexpectedEof));
1903                }
1904            }
1905        }
1906
1907        Ok(partial)
1908    }
1909
1910    /// Deserialize the value portion of a map entry
1911    fn deserialize_map_entry_value<'facet>(
1912        &mut self,
1913        partial: Partial<'facet>,
1914        element_name: &QName,
1915        _attributes: &[(QName, String)],
1916    ) -> Result<Partial<'facet>> {
1917        let mut partial = partial;
1918        let shape = partial.shape();
1919
1920        // For scalar values, read text content
1921        if matches!(&shape.def, Def::Scalar) {
1922            let text = self.read_text_until_end(element_name)?;
1923            partial = self.set_scalar_value(partial, &text)?;
1924            return Ok(partial);
1925        }
1926
1927        // For complex values, read the element content
1928        // This is a simplified version - complex map values would need more work
1929        let text = self.read_text_until_end(element_name)?;
1930        if shape.is_type::<String>() {
1931            partial = partial.set(text)?;
1932        } else {
1933            partial = self.set_scalar_value(partial, &text)?;
1934        }
1935
1936        Ok(partial)
1937    }
1938
1939    /// Deserialize a child element into the appropriate field.
1940    #[allow(clippy::too_many_arguments)]
1941    fn deserialize_child_element<'facet>(
1942        &mut self,
1943        partial: Partial<'facet>,
1944        fields: &[Field],
1945        element_name: &QName,
1946        attributes: &[(QName, String)],
1947        span: SourceSpan,
1948        is_empty: bool,
1949        elements_field_started: &mut Option<usize>,
1950        deny_unknown: bool,
1951    ) -> Result<Partial<'facet>> {
1952        let mut partial = partial;
1953
1954        // Get container-level default namespace (xml::ns_all)
1955        let ns_all = partial.shape().xml_ns_all();
1956
1957        // First try to find a direct element field match.
1958        // Uses namespace-aware matching:
1959        // - If field has xml::ns, it must match exactly
1960        // - Otherwise, if container has xml::ns_all, use that
1961        // - Otherwise, match any namespace
1962        if let Some((idx, field)) = fields.iter().enumerate().find(|(_, f)| {
1963            f.is_xml_element() && element_name.matches(local_name_of(f.name), f.xml_ns().or(ns_all))
1964        }) {
1965            log::trace!("matched element {} to field {}", element_name, field.name);
1966
1967            // End any open elements list field
1968            // Note: begin_list() doesn't push a frame, so we only end the field
1969            if elements_field_started.is_some() {
1970                partial = partial.end()?; // end previous field
1971                *elements_field_started = None;
1972            }
1973
1974            partial = partial.begin_nth_field(idx)?;
1975
1976            // Check if field has custom deserialization - must check BEFORE navigating
1977            // into Option wrappers, because begin_custom_deserialization needs
1978            // the field context (parent_field()) to access proxy_shape().
1979            let has_custom_deser = field.proxy_convert_in_fn().is_some();
1980            if has_custom_deser {
1981                // When using proxy, the proxy type handles the full conversion including
1982                // any Option wrappers, so we deserialize directly into the proxy.
1983                partial = partial.begin_custom_deserialization()?;
1984                partial =
1985                    self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
1986                partial = partial.end()?; // end custom deserialization
1987            } else {
1988                // No proxy - handle Option<T> wrapper manually
1989                let is_option = matches!(&partial.shape().def, Def::Option(_));
1990                if is_option {
1991                    partial = partial.begin_some()?;
1992                }
1993
1994                // Deserialize the element content
1995                partial =
1996                    self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
1997
1998                // End Option<T> if needed
1999                if is_option {
2000                    partial = partial.end()?; // end Some
2001                }
2002            }
2003
2004            partial = partial.end()?; // end field
2005            return Ok(partial);
2006        }
2007
2008        // Try to find an elements (list) field that accepts this element
2009        // We check: 1) if the item type accepts this element name, or
2010        //           2) if the field name matches the element name (fallback)
2011        // Uses namespace-aware matching for field name comparison.
2012        if let Some((idx, _field)) = fields.iter().enumerate().find(|(_, f)| {
2013            if !f.is_xml_elements() {
2014                return false;
2015            }
2016            // First, check if field name matches element name (common case for Vec<T>)
2017            // Uses namespace-aware matching with ns_all fallback.
2018            if element_name.matches(
2019                local_name_of(get_field_display_name(f)),
2020                f.xml_ns().or(ns_all),
2021            ) {
2022                return true;
2023            }
2024            // Otherwise, check if the list item type accepts this element
2025            let field_shape = f.shape();
2026            if let Some(item_shape) = get_list_item_shape(field_shape) {
2027                shape_accepts_element(item_shape, &element_name.local_name)
2028            } else {
2029                // Not a list type - shouldn't happen for xml::elements
2030                false
2031            }
2032        }) {
2033            // If we haven't started this list yet, begin it
2034            if elements_field_started.is_none() || *elements_field_started != Some(idx) {
2035                // End previous list field if any
2036                // Note: begin_list() doesn't push a frame, so we only end the field
2037                if elements_field_started.is_some() {
2038                    partial = partial.end()?; // end previous field
2039                }
2040
2041                partial = partial.begin_nth_field(idx)?;
2042                partial = partial.begin_list()?;
2043                *elements_field_started = Some(idx);
2044            }
2045
2046            // Add item to list
2047            partial = partial.begin_list_item()?;
2048            partial =
2049                self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
2050            partial = partial.end()?; // end list item
2051
2052            return Ok(partial);
2053        }
2054
2055        // No matching field found
2056        if deny_unknown {
2057            // Unknown element when deny_unknown_fields is set
2058            let expected: Vec<&'static str> = fields
2059                .iter()
2060                .filter(|f| f.is_xml_element() || f.is_xml_elements())
2061                .map(|f| f.name)
2062                .collect();
2063            return Err(self.err_at(
2064                XmlErrorKind::UnknownField {
2065                    field: element_name.to_string(),
2066                    expected,
2067                },
2068                span,
2069            ));
2070        }
2071
2072        // Skip this element
2073        log::trace!("skipping unknown element: {element_name}");
2074        if !is_empty {
2075            self.skip_element(element_name)?;
2076        }
2077        Ok(partial)
2078    }
2079
2080    /// Set the text content field.
2081    fn set_text_field<'facet>(
2082        &mut self,
2083        partial: Partial<'facet>,
2084        fields: &[Field],
2085        text: &str,
2086    ) -> Result<Partial<'facet>> {
2087        let mut partial = partial;
2088
2089        // Trim leading/trailing whitespace from text content
2090        // (since we don't use quick-xml's trim_text, we do it here)
2091        let trimmed_text = text.trim();
2092
2093        // Find the text field
2094        if let Some((idx, _field)) = fields.iter().enumerate().find(|(_, f)| f.is_xml_text()) {
2095            partial = partial.begin_nth_field(idx)?;
2096
2097            // Handle Option<T>
2098            let is_option = matches!(&partial.shape().def, Def::Option(_));
2099            if is_option {
2100                partial = partial.begin_some()?;
2101            }
2102
2103            partial = partial.set(trimmed_text.to_string())?;
2104
2105            // End Option<T> if needed
2106            if is_option {
2107                partial = partial.end()?; // end Some
2108            }
2109
2110            partial = partial.end()?; // end field
2111        }
2112        // If no text field, ignore the text content
2113
2114        Ok(partial)
2115    }
2116
2117    /// Read text content until the end tag.
2118    ///
2119    /// Returns the accumulated text with leading/trailing whitespace trimmed.
2120    fn read_text_until_end(&mut self, element_name: &QName) -> Result<String> {
2121        let mut text = String::new();
2122
2123        loop {
2124            let Some(event) = self.next() else {
2125                return Err(self.err(XmlErrorKind::UnexpectedEof));
2126            };
2127
2128            match event.event {
2129                OwnedEvent::End { ref name } if name == element_name => {
2130                    break;
2131                }
2132                OwnedEvent::Text { content } | OwnedEvent::CData { content } => {
2133                    text.push_str(&content);
2134                }
2135                other => {
2136                    return Err(self.err(XmlErrorKind::UnexpectedEvent(format!(
2137                        "expected text or end tag, got {other:?}"
2138                    ))));
2139                }
2140            }
2141        }
2142
2143        // Trim leading/trailing whitespace (since we don't use quick-xml's trim_text)
2144        Ok(text.trim().to_string())
2145    }
2146
2147    /// Skip an element and all its content.
2148    fn skip_element(&mut self, element_name: &QName) -> Result<()> {
2149        let mut depth = 1;
2150
2151        while depth > 0 {
2152            let Some(event) = self.next() else {
2153                return Err(self.err(XmlErrorKind::UnexpectedEof));
2154            };
2155
2156            match &event.event {
2157                OwnedEvent::Start { .. } => depth += 1,
2158                OwnedEvent::End { name } if name == element_name && depth == 1 => {
2159                    depth -= 1;
2160                }
2161                OwnedEvent::End { .. } => depth -= 1,
2162                OwnedEvent::Empty { .. } => {}
2163                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {}
2164                OwnedEvent::Eof => return Err(self.err(XmlErrorKind::UnexpectedEof)),
2165            }
2166        }
2167
2168        Ok(())
2169    }
2170
2171    /// Set defaults for any unset fields.
2172    fn set_defaults_for_unset_fields<'facet>(
2173        &self,
2174        partial: Partial<'facet>,
2175        fields: &[Field],
2176    ) -> Result<Partial<'facet>> {
2177        use facet_core::Characteristic;
2178        let mut partial = partial;
2179
2180        for (idx, field) in fields.iter().enumerate() {
2181            if partial.is_field_set(idx)? {
2182                continue;
2183            }
2184
2185            let field_has_default = field.has_default();
2186            let field_type_has_default = field.shape().is(Characteristic::Default);
2187            let should_skip = field.should_skip_deserializing();
2188            let field_is_option = matches!(field.shape().def, Def::Option(_));
2189
2190            if field_has_default || field_type_has_default || should_skip {
2191                log::trace!("setting default for unset field: {}", field.name);
2192                partial = partial.set_nth_field_to_default(idx)?;
2193            } else if field_is_option {
2194                log::trace!("initializing missing Option field `{}` to None", field.name);
2195                partial = partial.begin_field(field.name)?;
2196                partial = partial.set_default()?;
2197                partial = partial.end()?;
2198            }
2199        }
2200
2201        Ok(partial)
2202    }
2203
2204    /// Set a scalar value on the partial based on its type.
2205    fn set_scalar_value<'facet>(
2206        &self,
2207        partial: Partial<'facet>,
2208        value: &str,
2209    ) -> Result<Partial<'facet>> {
2210        let mut partial = partial;
2211        let shape = partial.shape();
2212
2213        // Priority 1: Check for builder_shape (immutable collections like Bytes -> BytesMut)
2214        if shape.builder_shape.is_some() {
2215            partial = partial.begin_inner()?;
2216            partial = self.set_scalar_value(partial, value)?;
2217            partial = partial.end()?;
2218            return Ok(partial);
2219        }
2220
2221        // Priority 2: Check for .inner (transparent wrappers like NonZero)
2222        // Collections (List/Map/Set/Array) have .inner for variance but shouldn't use this path
2223        if shape.inner.is_some()
2224            && !matches!(
2225                &shape.def,
2226                Def::List(_) | Def::Map(_) | Def::Set(_) | Def::Array(_)
2227            )
2228        {
2229            partial = partial.begin_inner()?;
2230            partial = self.set_scalar_value(partial, value)?;
2231            partial = partial.end()?;
2232            return Ok(partial);
2233        }
2234
2235        // Handle usize and isize explicitly before other numeric types
2236        if shape.is_type::<usize>() {
2237            let n: usize = value.parse().map_err(|_| {
2238                self.err(XmlErrorKind::InvalidValueForShape(format!(
2239                    "cannot parse `{value}` as usize"
2240                )))
2241            })?;
2242            partial = partial.set(n)?;
2243            return Ok(partial);
2244        }
2245
2246        if shape.is_type::<isize>() {
2247            let n: isize = value.parse().map_err(|_| {
2248                self.err(XmlErrorKind::InvalidValueForShape(format!(
2249                    "cannot parse `{value}` as isize"
2250                )))
2251            })?;
2252            partial = partial.set(n)?;
2253            return Ok(partial);
2254        }
2255
2256        // Try numeric types
2257        if let Type::Primitive(PrimitiveType::Numeric(numeric_type)) = shape.ty {
2258            let size = match shape.layout {
2259                ShapeLayout::Sized(layout) => layout.size(),
2260                ShapeLayout::Unsized => {
2261                    return Err(self.err(XmlErrorKind::InvalidValueForShape(
2262                        "cannot assign to unsized type".into(),
2263                    )));
2264                }
2265            };
2266
2267            return self.set_numeric_value(partial, value, numeric_type, size);
2268        }
2269
2270        // Boolean
2271        if shape.is_type::<bool>() {
2272            let b = match value.to_lowercase().as_str() {
2273                "true" | "1" | "yes" => true,
2274                "false" | "0" | "no" => false,
2275                _ => {
2276                    return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
2277                        "cannot parse `{value}` as boolean"
2278                    ))));
2279                }
2280            };
2281            partial = partial.set(b)?;
2282            return Ok(partial);
2283        }
2284
2285        // Char
2286        if shape.is_type::<char>() {
2287            let mut chars = value.chars();
2288            let c = chars.next().ok_or_else(|| {
2289                self.err(XmlErrorKind::InvalidValueForShape(
2290                    "empty string cannot be converted to char".into(),
2291                ))
2292            })?;
2293            if chars.next().is_some() {
2294                return Err(self.err(XmlErrorKind::InvalidValueForShape(
2295                    "string has more than one character".into(),
2296                )));
2297            }
2298            partial = partial.set(c)?;
2299            return Ok(partial);
2300        }
2301
2302        // String
2303        if shape.is_type::<String>() {
2304            partial = partial.set(value.to_string())?;
2305            return Ok(partial);
2306        }
2307
2308        // Try parse_from_str for other types (IpAddr, DateTime, etc.)
2309        if partial.shape().vtable.has_parse() {
2310            partial = partial
2311                .parse_from_str(value)
2312                .map_err(|e| self.err(XmlErrorKind::Reflect(e)))?;
2313            return Ok(partial);
2314        }
2315
2316        // Last resort: try setting as string
2317        partial = partial
2318            .set(value.to_string())
2319            .map_err(|e| self.err(XmlErrorKind::Reflect(e)))?;
2320
2321        Ok(partial)
2322    }
2323
2324    /// Set a numeric value with proper type conversion.
2325    fn set_numeric_value<'facet>(
2326        &self,
2327        partial: Partial<'facet>,
2328        value: &str,
2329        numeric_type: NumericType,
2330        size: usize,
2331    ) -> Result<Partial<'facet>> {
2332        let mut partial = partial;
2333        match numeric_type {
2334            NumericType::Integer { signed: false } => {
2335                let n: u64 = value.parse().map_err(|_| {
2336                    self.err(XmlErrorKind::InvalidValueForShape(format!(
2337                        "cannot parse `{value}` as unsigned integer"
2338                    )))
2339                })?;
2340
2341                match size {
2342                    1 => {
2343                        let v = u8::try_from(n).map_err(|_| {
2344                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2345                                "`{value}` out of range for u8"
2346                            )))
2347                        })?;
2348                        partial = partial.set(v)?;
2349                    }
2350                    2 => {
2351                        let v = u16::try_from(n).map_err(|_| {
2352                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2353                                "`{value}` out of range for u16"
2354                            )))
2355                        })?;
2356                        partial = partial.set(v)?;
2357                    }
2358                    4 => {
2359                        let v = u32::try_from(n).map_err(|_| {
2360                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2361                                "`{value}` out of range for u32"
2362                            )))
2363                        })?;
2364                        partial = partial.set(v)?;
2365                    }
2366                    8 => {
2367                        partial = partial.set(n)?;
2368                    }
2369                    16 => {
2370                        let n: u128 = value.parse().map_err(|_| {
2371                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2372                                "cannot parse `{value}` as u128"
2373                            )))
2374                        })?;
2375                        partial = partial.set(n)?;
2376                    }
2377                    _ => {
2378                        return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
2379                            "unsupported unsigned integer size: {size}"
2380                        ))));
2381                    }
2382                }
2383            }
2384            NumericType::Integer { signed: true } => {
2385                let n: i64 = value.parse().map_err(|_| {
2386                    self.err(XmlErrorKind::InvalidValueForShape(format!(
2387                        "cannot parse `{value}` as signed integer"
2388                    )))
2389                })?;
2390
2391                match size {
2392                    1 => {
2393                        let v = i8::try_from(n).map_err(|_| {
2394                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2395                                "`{value}` out of range for i8"
2396                            )))
2397                        })?;
2398                        partial = partial.set(v)?;
2399                    }
2400                    2 => {
2401                        let v = i16::try_from(n).map_err(|_| {
2402                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2403                                "`{value}` out of range for i16"
2404                            )))
2405                        })?;
2406                        partial = partial.set(v)?;
2407                    }
2408                    4 => {
2409                        let v = i32::try_from(n).map_err(|_| {
2410                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2411                                "`{value}` out of range for i32"
2412                            )))
2413                        })?;
2414                        partial = partial.set(v)?;
2415                    }
2416                    8 => {
2417                        partial = partial.set(n)?;
2418                    }
2419                    16 => {
2420                        let n: i128 = value.parse().map_err(|_| {
2421                            self.err(XmlErrorKind::InvalidValueForShape(format!(
2422                                "cannot parse `{value}` as i128"
2423                            )))
2424                        })?;
2425                        partial = partial.set(n)?;
2426                    }
2427                    _ => {
2428                        return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
2429                            "unsupported signed integer size: {size}"
2430                        ))));
2431                    }
2432                }
2433            }
2434            NumericType::Float => match size {
2435                4 => {
2436                    let v: f32 = value.parse().map_err(|_| {
2437                        self.err(XmlErrorKind::InvalidValueForShape(format!(
2438                            "cannot parse `{value}` as f32"
2439                        )))
2440                    })?;
2441                    partial = partial.set(v)?;
2442                }
2443                8 => {
2444                    let v: f64 = value.parse().map_err(|_| {
2445                        self.err(XmlErrorKind::InvalidValueForShape(format!(
2446                            "cannot parse `{value}` as f64"
2447                        )))
2448                    })?;
2449                    partial = partial.set(v)?;
2450                }
2451                _ => {
2452                    return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
2453                        "unsupported float size: {size}"
2454                    ))));
2455                }
2456            },
2457        }
2458
2459        Ok(partial)
2460    }
2461
2462    /// Deserialize adjacently tagged enum content.
2463    /// Format: <Element tag="Variant"><content>...</content></Element>
2464    fn deserialize_adjacently_tagged_content<'facet>(
2465        &mut self,
2466        partial: Partial<'facet>,
2467        variant: &Variant,
2468        content_tag: &str,
2469        parent_element_name: &QName,
2470    ) -> Result<Partial<'facet>> {
2471        let mut partial = partial;
2472        let variant_fields = variant.data.fields;
2473
2474        loop {
2475            let Some(event) = self.next() else {
2476                return Err(self.err(XmlErrorKind::UnexpectedEof));
2477            };
2478
2479            let span = event.span();
2480
2481            match event.event {
2482                OwnedEvent::End { ref name } if name == parent_element_name => {
2483                    // End of wrapper - set defaults for unset fields
2484                    partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
2485                    break;
2486                }
2487                OwnedEvent::Start {
2488                    ref name,
2489                    ref attributes,
2490                } if name == content_tag => {
2491                    // Found content element - deserialize based on variant kind
2492                    match variant.data.kind {
2493                        StructKind::Unit => {
2494                            // Unit variant - skip content
2495                            self.skip_element(name)?;
2496                        }
2497                        StructKind::Tuple | StructKind::TupleStruct => {
2498                            partial =
2499                                self.deserialize_tuple_content(partial, variant_fields, name)?;
2500                        }
2501                        StructKind::Struct => {
2502                            partial = self.deserialize_attributes(
2503                                partial,
2504                                variant_fields,
2505                                attributes,
2506                                false,
2507                                span,
2508                            )?;
2509                            partial = self.deserialize_element_content(
2510                                partial,
2511                                variant_fields,
2512                                name,
2513                                false,
2514                            )?;
2515                        }
2516                    }
2517                    partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
2518                }
2519                OwnedEvent::Empty {
2520                    ref name,
2521                    ref attributes,
2522                } if name == content_tag => {
2523                    // Empty content element
2524                    match variant.data.kind {
2525                        StructKind::Unit => {}
2526                        StructKind::Struct => {
2527                            partial = self.deserialize_attributes(
2528                                partial,
2529                                variant_fields,
2530                                attributes,
2531                                false,
2532                                span,
2533                            )?;
2534                        }
2535                        _ => {}
2536                    }
2537                    partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
2538                }
2539                OwnedEvent::Text { ref content } if content.trim().is_empty() => {
2540                    // Skip whitespace
2541                    continue;
2542                }
2543                _ => {
2544                    return Err(self.err_at(
2545                        XmlErrorKind::UnexpectedEvent(format!(
2546                            "expected content element <{}>, got {:?}",
2547                            content_tag, event.event
2548                        )),
2549                        span,
2550                    ));
2551                }
2552            }
2553        }
2554
2555        Ok(partial)
2556    }
2557
2558    /// Deserialize untagged enum - try each variant until one succeeds.
2559    fn deserialize_untagged_enum<'facet>(
2560        &mut self,
2561        partial: Partial<'facet>,
2562        enum_type: &EnumType,
2563        element_name: &QName,
2564        attributes: &[(QName, String)],
2565        span: SourceSpan,
2566        is_empty: bool,
2567    ) -> Result<Partial<'facet>> {
2568        // For untagged enums, we need to try each variant
2569        // This is tricky because we can't easily "rewind" the partial
2570        // For now, we'll use a simple heuristic based on available fields
2571
2572        // Collect child element names to help determine variant
2573        let saved_pos = self.pos;
2574
2575        // For untagged enums, try variants in order
2576        for variant in enum_type.variants.iter() {
2577            // Try to match this variant
2578            self.pos = saved_pos; // Reset position for each attempt
2579
2580            // Allocate a fresh partial for this attempt
2581            let attempt_partial = Partial::alloc_shape(partial.shape())?;
2582            let attempt_partial = attempt_partial.select_variant_named(variant.name)?;
2583
2584            // Try to deserialize into this variant
2585            let result = self.try_deserialize_variant(
2586                attempt_partial,
2587                variant,
2588                element_name,
2589                attributes,
2590                span,
2591                is_empty,
2592            );
2593
2594            if result.is_ok() {
2595                // Successfully matched - return this partial
2596                // But we need to transfer the data to the original partial
2597                // This is complex with the current API, so we return the new one
2598                return result;
2599            }
2600        }
2601
2602        // No variant matched
2603        Err(self.err_at(
2604            XmlErrorKind::InvalidValueForShape("no variant matched for untagged enum".to_string()),
2605            span,
2606        ))
2607    }
2608
2609    /// Try to deserialize a specific variant.
2610    fn try_deserialize_variant<'facet>(
2611        &mut self,
2612        partial: Partial<'facet>,
2613        variant: &Variant,
2614        element_name: &QName,
2615        attributes: &[(QName, String)],
2616        span: SourceSpan,
2617        is_empty: bool,
2618    ) -> Result<Partial<'facet>> {
2619        let mut partial = partial;
2620        let variant_fields = variant.data.fields;
2621
2622        match variant.data.kind {
2623            StructKind::Unit => {
2624                // Unit variant - nothing to deserialize
2625                if !is_empty {
2626                    self.skip_element(element_name)?;
2627                }
2628            }
2629            StructKind::Tuple | StructKind::TupleStruct => {
2630                if !is_empty {
2631                    partial =
2632                        self.deserialize_tuple_content(partial, variant_fields, element_name)?;
2633                }
2634                partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
2635            }
2636            StructKind::Struct => {
2637                partial =
2638                    self.deserialize_attributes(partial, variant_fields, attributes, false, span)?;
2639                if !is_empty {
2640                    partial = self.deserialize_element_content(
2641                        partial,
2642                        variant_fields,
2643                        element_name,
2644                        false,
2645                    )?;
2646                }
2647                partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
2648            }
2649        }
2650
2651        Ok(partial)
2652    }
2653
2654    /// Check if a struct has any flattened fields.
2655    fn has_flatten_fields(struct_def: &StructType) -> bool {
2656        struct_def.fields.iter().any(|f| f.is_flattened())
2657    }
2658
2659    /// Deserialize a struct with flattened fields using facet-solver.
2660    ///
2661    /// This uses a two-pass approach:
2662    /// 1. Peek mode: Scan all element names and attributes, feed to solver
2663    /// 2. Deserialize: Use the resolved Configuration to deserialize with proper path handling
2664    fn deserialize_struct_with_flatten<'facet>(
2665        &mut self,
2666        partial: Partial<'facet>,
2667        struct_def: &StructType,
2668        element_name: &QName,
2669        attributes: &[(QName, String)],
2670        span: SourceSpan,
2671        is_empty: bool,
2672    ) -> Result<Partial<'facet>> {
2673        let mut partial = partial;
2674
2675        log::trace!(
2676            "deserialize_struct_with_flatten: {}",
2677            partial.shape().type_identifier
2678        );
2679
2680        // Build the schema for this type
2681        let schema = Schema::build_auto(partial.shape())
2682            .map_err(|e| self.err_at(XmlErrorKind::SchemaError(e), span))?;
2683
2684        // Create the solver
2685        let mut solver = Solver::new(&schema);
2686
2687        // Feed attribute names to solver
2688        for (attr_name, _) in attributes {
2689            let _decision = solver.see_key(attr_name.local_name.clone());
2690        }
2691
2692        // Track child element positions for pass 2
2693        let mut element_positions: Vec<(String, usize)> = Vec::new();
2694        let saved_pos = self.pos;
2695
2696        // ========== PASS 1: Peek mode - scan all child elements ==========
2697        if !is_empty {
2698            loop {
2699                let Some(event) = self.next() else {
2700                    return Err(self.err(XmlErrorKind::UnexpectedEof));
2701                };
2702
2703                match &event.event {
2704                    OwnedEvent::End { name } if name == element_name => {
2705                        break;
2706                    }
2707                    OwnedEvent::Start { name, .. } | OwnedEvent::Empty { name, .. } => {
2708                        // Record position before this element
2709                        let elem_pos = self.pos - 1; // We already consumed this event
2710
2711                        let key = name.local_name.clone();
2712                        let _decision = solver.see_key(key.clone());
2713                        element_positions.push((key, elem_pos));
2714
2715                        // Skip the element content if it's a Start event
2716                        if matches!(&event.event, OwnedEvent::Start { .. }) {
2717                            self.skip_element(name)?;
2718                        }
2719                    }
2720                    OwnedEvent::Text { content } if content.trim().is_empty() => {
2721                        // Skip whitespace
2722                        continue;
2723                    }
2724                    OwnedEvent::Text { .. } => {
2725                        // Text content - might be for a text field
2726                        // For now we skip it in the peek pass
2727                        continue;
2728                    }
2729                    _ => {
2730                        return Err(self.err_at(
2731                            XmlErrorKind::UnexpectedEvent(format!(
2732                                "expected element or end tag, got {:?}",
2733                                event.event
2734                            )),
2735                            event.span(),
2736                        ));
2737                    }
2738                }
2739            }
2740        }
2741
2742        // ========== Get the resolved Configuration ==========
2743        let config = solver
2744            .finish()
2745            .map_err(|e| self.err_at(XmlErrorKind::Solver(e), span))?;
2746
2747        // ========== PASS 2: Deserialize with proper path handling ==========
2748
2749        // First, handle attributes using the configuration
2750        for (attr_name, attr_value) in attributes {
2751            if let Some(field_info) = config.resolution().field(&attr_name.local_name) {
2752                let segments = field_info.path.segments();
2753
2754                // Navigate to the field through the path, tracking Option fields
2755                let mut option_count = 0;
2756                for segment in segments {
2757                    match segment {
2758                        PathSegment::Field(name) => {
2759                            partial = partial.begin_field(name)?;
2760                            // Handle Option fields
2761                            if matches!(partial.shape().def, Def::Option(_)) {
2762                                partial = partial.begin_some()?;
2763                                option_count += 1;
2764                            }
2765                        }
2766                        PathSegment::Variant(_, variant_name) => {
2767                            partial = partial.select_variant_named(variant_name)?;
2768                        }
2769                    }
2770                }
2771
2772                // Handle Spanned<T>
2773                if is_spanned_shape(partial.shape()) {
2774                    partial = partial.begin_field("value")?;
2775                }
2776
2777                // Deserialize the attribute value
2778                partial = self.set_scalar_value(partial, attr_value)?;
2779
2780                // Unwind: end Spanned if needed
2781                if is_spanned_shape(partial.shape()) {
2782                    partial = partial.end()?;
2783                }
2784
2785                // Unwind the path (including Option Some wrappers)
2786                for _ in 0..option_count {
2787                    partial = partial.end()?; // end Some
2788                }
2789                for segment in segments.iter().rev() {
2790                    if matches!(segment, PathSegment::Field(_)) {
2791                        partial = partial.end()?;
2792                    }
2793                }
2794            }
2795        }
2796
2797        // Handle elements using the configuration
2798        // Reset position to replay elements
2799        self.pos = saved_pos;
2800
2801        if !is_empty {
2802            loop {
2803                let Some(event) = self.next() else {
2804                    return Err(self.err(XmlErrorKind::UnexpectedEof));
2805                };
2806
2807                let event_span = event.span();
2808
2809                match event.event {
2810                    OwnedEvent::End { ref name } if name == element_name => {
2811                        break;
2812                    }
2813                    OwnedEvent::Start {
2814                        ref name,
2815                        ref attributes,
2816                    }
2817                    | OwnedEvent::Empty {
2818                        ref name,
2819                        ref attributes,
2820                    } => {
2821                        let is_elem_empty = matches!(event.event, OwnedEvent::Empty { .. });
2822
2823                        if let Some(field_info) = config.resolution().field(&name.local_name) {
2824                            let segments = field_info.path.segments();
2825
2826                            // Navigate to the field through the path, tracking Option fields
2827                            let mut option_count = 0;
2828                            for segment in segments {
2829                                match segment {
2830                                    PathSegment::Field(field_name) => {
2831                                        partial = partial.begin_field(field_name)?;
2832                                        // Handle Option fields
2833                                        if matches!(partial.shape().def, Def::Option(_)) {
2834                                            partial = partial.begin_some()?;
2835                                            option_count += 1;
2836                                        }
2837                                    }
2838                                    PathSegment::Variant(_, variant_name) => {
2839                                        partial = partial.select_variant_named(variant_name)?;
2840                                    }
2841                                }
2842                            }
2843
2844                            // Deserialize the element
2845                            partial = self.deserialize_element(
2846                                partial,
2847                                name,
2848                                attributes,
2849                                event_span,
2850                                is_elem_empty,
2851                            )?;
2852
2853                            // Unwind the path (including Option Some wrappers)
2854                            for _ in 0..option_count {
2855                                partial = partial.end()?; // end Some
2856                            }
2857                            for segment in segments.iter().rev() {
2858                                if matches!(segment, PathSegment::Field(_)) {
2859                                    partial = partial.end()?;
2860                                }
2861                            }
2862                        } else {
2863                            // Unknown element - skip it
2864                            if !is_elem_empty {
2865                                self.skip_element(name)?;
2866                            }
2867                        }
2868                    }
2869                    OwnedEvent::Text { ref content } if content.trim().is_empty() => {
2870                        continue;
2871                    }
2872                    OwnedEvent::Text { .. } => {
2873                        // Text content - handle if there's a text field
2874                        // For now skip
2875                        continue;
2876                    }
2877                    _ => {
2878                        return Err(self.err_at(
2879                            XmlErrorKind::UnexpectedEvent(format!(
2880                                "expected element or end tag, got {:?}",
2881                                event.event
2882                            )),
2883                            event_span,
2884                        ));
2885                    }
2886                }
2887            }
2888        }
2889
2890        // Set defaults for any unset fields
2891        partial = self.set_defaults_for_unset_fields(partial, struct_def.fields)?;
2892
2893        Ok(partial)
2894    }
2895}