• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 19921098942

04 Dec 2025 07:27AM UTC coverage: 57.083% (-2.1%) from 59.134%
19921098942

Pull #1015

github

web-flow
Merge ee47a41e8 into 0012fd8ca
Pull Request #1015: feat: add facet-xml crate for XML serialization/deserialization

504 of 2176 new or added lines in 3 files covered. (23.16%)

3 existing lines in 1 file now uncovered.

21465 of 37603 relevant lines covered (57.08%)

514.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.05
/facet-xml/src/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

6
use base64::Engine;
7
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
8
use facet_core::{
9
    Def, EnumType, Facet, Field, NumericType, PrimitiveType, ShapeLayout, StructKind, StructType,
10
    Type, UserType, Variant,
11
};
12
use facet_reflect::{Partial, is_spanned_shape};
13
use facet_solver::{PathSegment, Schema, Solver};
14
use miette::SourceSpan;
15
use quick_xml::Reader;
16
use quick_xml::events::{BytesStart, Event};
17

18
use crate::error::{XmlError, XmlErrorKind};
19

20
pub(crate) type Result<T> = std::result::Result<T, XmlError>;
21

22
/// Get the display name for a variant (respecting `rename` attribute).
23
fn get_variant_display_name(variant: &Variant) -> &'static str {
49✔
24
    if let Some(attr) = variant.get_builtin_attr("rename") {
49✔
25
        if let Some(&renamed) = attr.get_as::<&str>() {
49✔
26
            return renamed;
49✔
NEW
27
        }
×
NEW
28
    }
×
NEW
29
    variant.name
×
30
}
49✔
31

32
/// Get the display name for a shape (respecting `rename` attribute).
33
fn get_shape_display_name(shape: &facet_core::Shape) -> &'static str {
2✔
34
    if let Some(renamed) = shape.get_builtin_attr_value::<&str>("rename") {
2✔
35
        return renamed;
1✔
36
    }
1✔
37
    shape.type_identifier
1✔
38
}
2✔
39

40
/// Get the display name for a field (respecting `rename` attribute).
41
fn get_field_display_name(field: &Field) -> &'static str {
38✔
42
    if let Some(attr) = field.get_builtin_attr("rename") {
38✔
43
        if let Some(&renamed) = attr.get_as::<&str>() {
6✔
44
            return renamed;
6✔
NEW
45
        }
×
46
    }
32✔
47
    field.name
32✔
48
}
38✔
49

50
/// Check if a shape can accept an element with the given name.
51
/// For structs: element name must match struct's display name.
52
/// For enums: element name must match one of the variant's display names.
53
fn shape_accepts_element(shape: &facet_core::Shape, element_name: &str) -> bool {
14✔
54
    match &shape.ty {
14✔
55
        Type::User(UserType::Enum(enum_type)) => {
12✔
56
            // For enums, check if element name matches any variant
57
            enum_type
12✔
58
                .variants
12✔
59
                .iter()
12✔
60
                .any(|v| get_variant_display_name(v) == element_name)
24✔
61
        }
62
        Type::User(UserType::Struct(_)) => {
63
            // For structs, check if element name matches struct's name
64
            get_shape_display_name(shape) == element_name
2✔
65
        }
66
        _ => {
67
            // For other types (opaque, etc.), use type identifier
NEW
68
            shape.type_identifier == element_name
×
69
        }
70
    }
71
}
14✔
72

73
/// Get the list item shape from a field's shape (if it's a list type).
74
fn get_list_item_shape(shape: &facet_core::Shape) -> Option<&'static facet_core::Shape> {
14✔
75
    match &shape.def {
14✔
76
        Def::List(list_def) => Some(list_def.t()),
14✔
NEW
77
        _ => None,
×
78
    }
79
}
14✔
80

81
// ============================================================================
82
// Public API
83
// ============================================================================
84

85
/// Deserialize an XML string into a value of type `T`.
86
///
87
/// # Example
88
///
89
/// ```
90
/// use facet::Facet;
91
/// use facet_xml as xml;
92
///
93
/// #[derive(Facet, Debug, PartialEq)]
94
/// struct Person {
95
///     #[facet(xml::attribute)]
96
///     id: u32,
97
///     #[facet(xml::element)]
98
///     name: String,
99
/// }
100
///
101
/// let xml_str = r#"<Person id="42"><name>Alice</name></Person>"#;
102
/// let person: Person = facet_xml::from_str(xml_str).unwrap();
103
/// assert_eq!(person.name, "Alice");
104
/// assert_eq!(person.id, 42);
105
/// ```
106
pub fn from_str<'input, 'facet, T>(xml: &'input str) -> Result<T>
15✔
107
where
15✔
108
    T: Facet<'facet>,
15✔
109
    'input: 'facet,
15✔
110
{
111
    log::trace!(
15✔
112
        "from_str: parsing XML for type {}",
NEW
113
        core::any::type_name::<T>()
×
114
    );
115

116
    let mut deserializer = XmlDeserializer::new(xml)?;
15✔
117
    let partial = Partial::alloc::<T>()?;
15✔
118

119
    let partial = deserializer.deserialize_document(partial)?;
15✔
120

121
    let result = partial
15✔
122
        .build()
15✔
123
        .map_err(|e| XmlError::new(XmlErrorKind::Reflect(e)).with_source(xml))?
15✔
124
        .materialize()
15✔
125
        .map_err(|e| XmlError::new(XmlErrorKind::Reflect(e)).with_source(xml))?;
15✔
126

127
    Ok(result)
15✔
128
}
15✔
129

130
/// Deserialize an XML byte slice into a value of type `T`.
131
///
132
/// This is a convenience wrapper around [`from_str`] that first validates
133
/// that the input is valid UTF-8.
134
///
135
/// # Example
136
///
137
/// ```
138
/// use facet::Facet;
139
/// use facet_xml as xml;
140
///
141
/// #[derive(Facet, Debug, PartialEq)]
142
/// struct Person {
143
///     #[facet(xml::attribute)]
144
///     id: u32,
145
///     #[facet(xml::element)]
146
///     name: String,
147
/// }
148
///
149
/// let xml_bytes = b"<Person id=\"42\"><name>Alice</name></Person>";
150
/// let person: Person = facet_xml::from_slice(xml_bytes).unwrap();
151
/// assert_eq!(person.name, "Alice");
152
/// assert_eq!(person.id, 42);
153
/// ```
NEW
154
pub fn from_slice<'input, 'facet, T>(xml: &'input [u8]) -> Result<T>
×
NEW
155
where
×
NEW
156
    T: Facet<'facet>,
×
NEW
157
    'input: 'facet,
×
158
{
NEW
159
    let xml_str = std::str::from_utf8(xml)
×
NEW
160
        .map_err(|e| XmlError::new(XmlErrorKind::InvalidUtf8(e.to_string())))?;
×
NEW
161
    from_str(xml_str)
×
NEW
162
}
×
163

164
// ============================================================================
165
// Extension trait for XML-specific field attributes
166
// ============================================================================
167

168
/// Extension trait for Field to check XML-specific attributes.
169
pub(crate) trait XmlFieldExt {
170
    /// Returns true if this field is an element field.
171
    fn is_xml_element(&self) -> bool;
172
    /// Returns true if this field is an elements (list) field.
173
    fn is_xml_elements(&self) -> bool;
174
    /// Returns true if this field is an attribute field.
175
    fn is_xml_attribute(&self) -> bool;
176
    /// Returns true if this field is a text field.
177
    fn is_xml_text(&self) -> bool;
178
    /// Returns true if this field stores the element name.
179
    #[allow(dead_code)]
180
    fn is_xml_element_name(&self) -> bool;
181
}
182

183
impl XmlFieldExt for Field {
184
    fn is_xml_element(&self) -> bool {
292✔
185
        self.is_child() || self.has_attr(Some("xml"), "element")
292✔
186
    }
292✔
187

188
    fn is_xml_elements(&self) -> bool {
98✔
189
        self.has_attr(Some("xml"), "elements")
98✔
190
    }
98✔
191

192
    fn is_xml_attribute(&self) -> bool {
154✔
193
        self.has_attr(Some("xml"), "attribute")
154✔
194
    }
154✔
195

196
    fn is_xml_text(&self) -> bool {
11✔
197
        self.has_attr(Some("xml"), "text")
11✔
198
    }
11✔
199

NEW
200
    fn is_xml_element_name(&self) -> bool {
×
NEW
201
        self.has_attr(Some("xml"), "element_name")
×
NEW
202
    }
×
203
}
204

205
// ============================================================================
206
// Event wrapper with owned strings
207
// ============================================================================
208

209
/// An XML event with owned string data and span information.
210
#[derive(Debug, Clone)]
211
enum OwnedEvent {
212
    /// Start of an element with tag name and attributes
213
    Start {
214
        name: String,
215
        attributes: Vec<(String, String)>,
216
    },
217
    /// End of an element
218
    End { name: String },
219
    /// Empty element (self-closing)
220
    Empty {
221
        name: String,
222
        attributes: Vec<(String, String)>,
223
    },
224
    /// Text content
225
    Text { content: String },
226
    /// CDATA content
227
    CData { content: String },
228
    /// End of file
229
    Eof,
230
}
231

232
#[derive(Debug, Clone)]
233
struct SpannedEvent {
234
    event: OwnedEvent,
235
    /// Byte offset in the original input where this event starts.
236
    offset: usize,
237
    /// Length of the event in bytes.
238
    len: usize,
239
}
240

241
impl SpannedEvent {
242
    fn span(&self) -> SourceSpan {
164✔
243
        SourceSpan::from((self.offset, self.len))
164✔
244
    }
164✔
245
}
246

247
// ============================================================================
248
// Event Collector
249
// ============================================================================
250

251
/// Collects all events from the parser upfront.
252
struct EventCollector<'input> {
253
    reader: Reader<&'input [u8]>,
254
    input: &'input str,
255
}
256

257
impl<'input> EventCollector<'input> {
258
    fn new(input: &'input str) -> Self {
18✔
259
        let mut reader = Reader::from_str(input);
18✔
260
        reader.config_mut().trim_text(true);
18✔
261
        Self { reader, input }
18✔
262
    }
18✔
263

264
    fn collect_all(mut self) -> Result<Vec<SpannedEvent>> {
18✔
265
        let mut events = Vec::new();
18✔
266
        let mut buf = Vec::new();
18✔
267

268
        loop {
269
            let offset = self.reader.buffer_position() as usize;
294✔
270
            let event = self.reader.read_event_into(&mut buf).map_err(|e| {
294✔
NEW
271
                XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
×
NEW
272
            })?;
×
273

274
            let (owned, len) = match event {
294✔
275
                Event::Start(e) => {
97✔
276
                    let name = String::from_utf8_lossy(e.name().as_ref()).into_owned();
97✔
277
                    let attributes = self.collect_attributes(&e)?;
97✔
278
                    let len = self.reader.buffer_position() as usize - offset;
97✔
279
                    (OwnedEvent::Start { name, attributes }, len)
97✔
280
                }
281
                Event::End(e) => {
97✔
282
                    let name = String::from_utf8_lossy(e.name().as_ref()).into_owned();
97✔
283
                    let len = self.reader.buffer_position() as usize - offset;
97✔
284
                    (OwnedEvent::End { name }, len)
97✔
285
                }
286
                Event::Empty(e) => {
22✔
287
                    let name = String::from_utf8_lossy(e.name().as_ref()).into_owned();
22✔
288
                    let attributes = self.collect_attributes(&e)?;
22✔
289
                    let len = self.reader.buffer_position() as usize - offset;
22✔
290
                    (OwnedEvent::Empty { name, attributes }, len)
22✔
291
                }
292
                Event::Text(e) => {
60✔
293
                    let content = e.unescape().map_err(|e| {
60✔
NEW
294
                        XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
×
NEW
295
                    })?;
×
296
                    if content.trim().is_empty() {
60✔
NEW
297
                        buf.clear();
×
NEW
298
                        continue; // Skip whitespace-only text
×
299
                    }
60✔
300
                    let len = self.reader.buffer_position() as usize - offset;
60✔
301
                    (
60✔
302
                        OwnedEvent::Text {
60✔
303
                            content: content.into_owned(),
60✔
304
                        },
60✔
305
                        len,
60✔
306
                    )
60✔
307
                }
NEW
308
                Event::CData(e) => {
×
NEW
309
                    let content = String::from_utf8_lossy(&e).into_owned();
×
NEW
310
                    let len = self.reader.buffer_position() as usize - offset;
×
NEW
311
                    (OwnedEvent::CData { content }, len)
×
312
                }
313
                Event::Eof => {
314
                    events.push(SpannedEvent {
18✔
315
                        event: OwnedEvent::Eof,
18✔
316
                        offset,
18✔
317
                        len: 0,
18✔
318
                    });
18✔
319
                    break;
18✔
320
                }
321
                Event::Comment(_) | Event::Decl(_) | Event::PI(_) | Event::DocType(_) => {
322
                    // Skip comments, declarations, processing instructions, doctypes
NEW
323
                    buf.clear();
×
NEW
324
                    continue;
×
325
                }
326
            };
327

328
            log::trace!("XML event: {owned:?} at offset {offset}");
276✔
329
            events.push(SpannedEvent {
276✔
330
                event: owned,
276✔
331
                offset,
276✔
332
                len,
276✔
333
            });
276✔
334
            buf.clear();
276✔
335
        }
336

337
        Ok(events)
18✔
338
    }
18✔
339

340
    fn collect_attributes(&self, e: &BytesStart<'_>) -> Result<Vec<(String, String)>> {
119✔
341
        let mut attrs = Vec::new();
119✔
342
        for attr in e.attributes() {
119✔
343
            let attr = attr.map_err(|e| {
83✔
NEW
344
                XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
×
NEW
345
            })?;
×
346
            let key = String::from_utf8_lossy(attr.key.as_ref()).into_owned();
83✔
347
            let value = attr
83✔
348
                .unescape_value()
83✔
349
                .map_err(|e| {
83✔
NEW
350
                    XmlError::new(XmlErrorKind::Parse(e.to_string())).with_source(self.input)
×
NEW
351
                })?
×
352
                .into_owned();
83✔
353
            attrs.push((key, value));
83✔
354
        }
355
        Ok(attrs)
119✔
356
    }
119✔
357
}
358

359
// ============================================================================
360
// Deserializer
361
// ============================================================================
362

363
/// XML deserializer that processes events from a collected event stream.
364
struct XmlDeserializer<'input> {
365
    input: &'input str,
366
    events: Vec<SpannedEvent>,
367
    pos: usize,
368
}
369

370
impl<'input> XmlDeserializer<'input> {
371
    /// Create a new deserializer by parsing the input and collecting all events.
372
    fn new(input: &'input str) -> Result<Self> {
18✔
373
        let collector = EventCollector::new(input);
18✔
374
        let events = collector.collect_all()?;
18✔
375

376
        Ok(Self {
18✔
377
            input,
18✔
378
            events,
18✔
379
            pos: 0,
18✔
380
        })
18✔
381
    }
18✔
382

383
    /// Create an error with source code attached for diagnostics.
NEW
384
    fn err(&self, kind: impl Into<XmlErrorKind>) -> XmlError {
×
NEW
385
        XmlError::new(kind).with_source(self.input.to_string())
×
NEW
386
    }
×
387

388
    /// Create an error with source code and span attached for diagnostics.
NEW
389
    fn err_at(&self, kind: impl Into<XmlErrorKind>, span: impl Into<SourceSpan>) -> XmlError {
×
NEW
390
        XmlError::new(kind)
×
NEW
391
            .with_source(self.input.to_string())
×
NEW
392
            .with_span(span)
×
NEW
393
    }
×
394

395
    /// Consume and return the current event (cloned to avoid borrow issues).
396
    fn next(&mut self) -> Option<SpannedEvent> {
276✔
397
        if self.pos < self.events.len() {
276✔
398
            let event = self.events[self.pos].clone();
276✔
399
            self.pos += 1;
276✔
400
            Some(event)
276✔
401
        } else {
NEW
402
            None
×
403
        }
404
    }
276✔
405

406
    /// Save current position for potential rewind.
407
    #[allow(dead_code)]
NEW
408
    fn save_position(&self) -> usize {
×
NEW
409
        self.pos
×
NEW
410
    }
×
411

412
    /// Restore to a previously saved position.
413
    #[allow(dead_code)]
NEW
414
    fn restore_position(&mut self, pos: usize) {
×
NEW
415
        self.pos = pos;
×
NEW
416
    }
×
417

418
    /// Deserialize the document starting from the root element.
419
    fn deserialize_document<'facet>(
18✔
420
        &mut self,
18✔
421
        partial: Partial<'facet>,
18✔
422
    ) -> Result<Partial<'facet>> {
18✔
423
        // Expect a start or empty element
424
        let Some(event) = self.next() else {
18✔
NEW
425
            return Err(self.err(XmlErrorKind::UnexpectedEof));
×
426
        };
427

428
        let span = event.span();
18✔
429

430
        match event.event {
18✔
431
            OwnedEvent::Start { name, attributes } => {
14✔
432
                self.deserialize_element(partial, &name, &attributes, span, false)
14✔
433
            }
434
            OwnedEvent::Empty { name, attributes } => {
4✔
435
                self.deserialize_element(partial, &name, &attributes, span, true)
4✔
436
            }
NEW
437
            other => Err(self.err(XmlErrorKind::UnexpectedEvent(format!(
×
NEW
438
                "expected start element, got {other:?}"
×
NEW
439
            )))),
×
440
        }
441
    }
18✔
442

443
    /// Deserialize an element into a partial value.
444
    fn deserialize_element<'facet>(
132✔
445
        &mut self,
132✔
446
        partial: Partial<'facet>,
132✔
447
        element_name: &str,
132✔
448
        attributes: &[(String, String)],
132✔
449
        span: SourceSpan,
132✔
450
        is_empty: bool,
132✔
451
    ) -> Result<Partial<'facet>> {
132✔
452
        let mut partial = partial;
132✔
453
        let shape = partial.shape();
132✔
454

455
        log::trace!(
132✔
456
            "deserialize_element: {} into shape {:?}",
457
            element_name,
458
            shape.ty
459
        );
460

461
        // Check Def first for scalars (String, etc.)
462
        if matches!(&shape.def, Def::Scalar) {
132✔
463
            // For scalar types, we expect text content
464
            if is_empty {
56✔
465
                // Empty element for a string means empty string
NEW
466
                if shape.is_type::<String>() {
×
NEW
467
                    partial = partial.set(String::new())?;
×
NEW
468
                    return Ok(partial);
×
NEW
469
                }
×
NEW
470
                return Err(self.err_at(
×
NEW
471
                    XmlErrorKind::InvalidValueForShape(
×
NEW
472
                        "expected text content for scalar type".into(),
×
NEW
473
                    ),
×
NEW
474
                    span,
×
NEW
475
                ));
×
476
            }
56✔
477

478
            // Get text content
479
            let text = self.read_text_until_end(element_name)?;
56✔
480
            partial = self.set_scalar_value(partial, &text)?;
56✔
481
            return Ok(partial);
56✔
482
        }
76✔
483

484
        // Handle transparent types (newtype wrappers)
485
        if shape.inner.is_some() {
76✔
NEW
486
            partial = partial.begin_inner()?;
×
NEW
487
            partial =
×
NEW
488
                self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
×
NEW
489
            partial = partial.end()?;
×
NEW
490
            return Ok(partial);
×
491
        }
76✔
492

493
        // Handle Vec<u8> as base64
494
        if let Def::List(list_def) = &shape.def {
76✔
NEW
495
            if list_def.t().is_type::<u8>() {
×
NEW
496
                if is_empty {
×
497
                    // Empty element = empty bytes
NEW
498
                    partial = partial.begin_list()?;
×
499
                    // Empty list, nothing to add
NEW
500
                    return Ok(partial);
×
NEW
501
                }
×
NEW
502
                let text = self.read_text_until_end(element_name)?;
×
NEW
503
                let bytes = BASE64_STANDARD
×
NEW
504
                    .decode(text.trim())
×
NEW
505
                    .map_err(|e| self.err_at(XmlErrorKind::Base64Decode(e.to_string()), span))?;
×
NEW
506
                partial = partial.begin_list()?;
×
NEW
507
                for byte in bytes {
×
NEW
508
                    partial = partial.begin_list_item()?;
×
NEW
509
                    partial = partial.set(byte)?;
×
NEW
510
                    partial = partial.end()?; // end list item
×
511
                }
NEW
512
                return Ok(partial);
×
NEW
513
            }
×
514
        }
76✔
515

516
        // Handle [u8; N] as base64
517
        if let Def::Array(arr_def) = &shape.def {
76✔
NEW
518
            if arr_def.t().is_type::<u8>() {
×
NEW
519
                if is_empty {
×
NEW
520
                    return Err(self.err_at(
×
NEW
521
                        XmlErrorKind::InvalidValueForShape("empty element for byte array".into()),
×
NEW
522
                        span,
×
NEW
523
                    ));
×
NEW
524
                }
×
NEW
525
                let text = self.read_text_until_end(element_name)?;
×
NEW
526
                let bytes = BASE64_STANDARD
×
NEW
527
                    .decode(text.trim())
×
NEW
528
                    .map_err(|e| self.err_at(XmlErrorKind::Base64Decode(e.to_string()), span))?;
×
NEW
529
                if bytes.len() != arr_def.n {
×
NEW
530
                    return Err(self.err_at(
×
NEW
531
                        XmlErrorKind::InvalidValueForShape(format!(
×
NEW
532
                            "base64 decoded {} bytes, expected {}",
×
NEW
533
                            bytes.len(),
×
NEW
534
                            arr_def.n
×
NEW
535
                        )),
×
NEW
536
                        span,
×
NEW
537
                    ));
×
NEW
538
                }
×
NEW
539
                for (idx, byte) in bytes.into_iter().enumerate() {
×
NEW
540
                    partial = partial.begin_nth_field(idx)?;
×
NEW
541
                    partial = partial.set(byte)?;
×
NEW
542
                    partial = partial.end()?;
×
543
                }
NEW
544
                return Ok(partial);
×
NEW
545
            }
×
546
        }
76✔
547

548
        // Handle fixed arrays (non-byte)
549
        if let Def::Array(arr_def) = &shape.def {
76✔
NEW
550
            if is_empty {
×
NEW
551
                return Err(self.err_at(
×
NEW
552
                    XmlErrorKind::InvalidValueForShape("empty element for array".into()),
×
NEW
553
                    span,
×
NEW
554
                ));
×
NEW
555
            }
×
NEW
556
            let array_len = arr_def.n;
×
NEW
557
            return self.deserialize_array_content(partial, array_len, element_name);
×
558
        }
76✔
559

560
        // Handle sets
561
        if matches!(&shape.def, Def::Set(_)) {
76✔
NEW
562
            if is_empty {
×
NEW
563
                partial = partial.begin_set()?;
×
564
                // Empty set - nothing to do
NEW
565
                return Ok(partial);
×
NEW
566
            }
×
NEW
567
            return self.deserialize_set_content(partial, element_name);
×
568
        }
76✔
569

570
        // Handle maps
571
        if matches!(&shape.def, Def::Map(_)) {
76✔
NEW
572
            if is_empty {
×
NEW
573
                partial = partial.begin_map()?;
×
574
                // Empty map - nothing to do
NEW
575
                return Ok(partial);
×
NEW
576
            }
×
NEW
577
            return self.deserialize_map_content(partial, element_name);
×
578
        }
76✔
579

580
        // Handle different shapes
581
        match &shape.ty {
76✔
582
            Type::User(UserType::Struct(struct_def)) => {
63✔
583
                // Get fields
584
                let fields = struct_def.fields;
63✔
585
                let deny_unknown = shape.has_deny_unknown_fields_attr();
63✔
586

587
                match struct_def.kind {
63✔
588
                    StructKind::Unit => {
589
                        // Unit struct - nothing to deserialize, just skip content
NEW
590
                        if !is_empty {
×
NEW
591
                            self.skip_element(element_name)?;
×
NEW
592
                        }
×
NEW
593
                        return Ok(partial);
×
594
                    }
595
                    StructKind::Tuple | StructKind::TupleStruct => {
596
                        // Tuple struct - deserialize fields by position
NEW
597
                        if is_empty {
×
598
                            // Set defaults for all fields
NEW
599
                            partial = self.set_defaults_for_unset_fields(partial, fields)?;
×
NEW
600
                            return Ok(partial);
×
NEW
601
                        }
×
602

603
                        // Deserialize tuple fields from child elements
NEW
604
                        partial = self.deserialize_tuple_content(partial, fields, element_name)?;
×
605

606
                        // Set defaults for any unset fields
NEW
607
                        partial = self.set_defaults_for_unset_fields(partial, fields)?;
×
NEW
608
                        return Ok(partial);
×
609
                    }
610
                    StructKind::Struct => {
611
                        // Check if this struct has flattened fields - if so, use the solver
612
                        if Self::has_flatten_fields(struct_def) {
63✔
NEW
613
                            return self.deserialize_struct_with_flatten(
×
NEW
614
                                partial,
×
NEW
615
                                struct_def,
×
NEW
616
                                element_name,
×
NEW
617
                                attributes,
×
NEW
618
                                span,
×
NEW
619
                                is_empty,
×
620
                            );
621
                        }
63✔
622
                        // Normal named struct - fall through to standard handling
623
                    }
624
                }
625

626
                // First, deserialize attributes
627
                partial =
63✔
628
                    self.deserialize_attributes(partial, fields, attributes, deny_unknown, span)?;
63✔
629

630
                // If empty element, we're done with content
631
                if is_empty {
63✔
632
                    // Set defaults for missing fields
633
                    partial = self.set_defaults_for_unset_fields(partial, fields)?;
22✔
634
                    return Ok(partial);
22✔
635
                }
41✔
636

637
                // Deserialize child elements and text content
638
                partial =
41✔
639
                    self.deserialize_element_content(partial, fields, element_name, deny_unknown)?;
41✔
640

641
                // Set defaults for any unset fields
642
                partial = self.set_defaults_for_unset_fields(partial, fields)?;
41✔
643

644
                Ok(partial)
41✔
645
            }
646
            Type::User(UserType::Enum(enum_def)) => {
13✔
647
                // Determine enum tagging strategy
648
                let is_untagged = shape.is_untagged();
13✔
649
                let tag_attr = shape.get_tag_attr();
13✔
650
                let content_attr = shape.get_content_attr();
13✔
651

652
                if is_untagged {
13✔
653
                    // Untagged: try each variant until one works
NEW
654
                    return self.deserialize_untagged_enum(
×
NEW
655
                        partial,
×
NEW
656
                        enum_def,
×
NEW
657
                        element_name,
×
NEW
658
                        attributes,
×
NEW
659
                        span,
×
NEW
660
                        is_empty,
×
661
                    );
662
                } else if let Some(tag) = tag_attr {
13✔
663
                    // Get variant name from attribute
NEW
664
                    let variant_name = attributes
×
NEW
665
                        .iter()
×
NEW
666
                        .find(|(k, _)| k == tag)
×
NEW
667
                        .map(|(_, v)| v.clone())
×
NEW
668
                        .ok_or_else(|| {
×
NEW
669
                            self.err_at(XmlErrorKind::MissingAttribute(tag.to_string()), span)
×
NEW
670
                        })?;
×
671

672
                    // Find the variant by name
NEW
673
                    let variant = enum_def
×
NEW
674
                        .variants
×
NEW
675
                        .iter()
×
NEW
676
                        .find(|v| v.name == variant_name)
×
NEW
677
                        .ok_or_else(|| {
×
NEW
678
                            self.err_at(XmlErrorKind::NoMatchingElement(variant_name.clone()), span)
×
NEW
679
                        })?;
×
680

681
                    // Select the variant
NEW
682
                    partial = partial.select_variant_named(&variant_name)?;
×
NEW
683
                    let variant_fields = variant.data.fields;
×
684

NEW
685
                    if let Some(content) = content_attr {
×
686
                        // Adjacently tagged: <Element tag="Variant"><content>...</content></Element>
NEW
687
                        if is_empty {
×
688
                            // No content element for empty element
NEW
689
                            partial =
×
NEW
690
                                self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
691
                        } else {
692
                            // Find the content element
NEW
693
                            partial = self.deserialize_adjacently_tagged_content(
×
NEW
694
                                partial,
×
NEW
695
                                variant,
×
NEW
696
                                content,
×
NEW
697
                                element_name,
×
NEW
698
                            )?;
×
699
                        }
700
                    } else {
701
                        // Internally tagged: <Element tag="Variant">...fields...</Element>
702
                        // Filter out the tag attribute
NEW
703
                        let other_attrs: Vec<_> = attributes
×
NEW
704
                            .iter()
×
NEW
705
                            .filter(|(k, _)| k != tag)
×
NEW
706
                            .cloned()
×
NEW
707
                            .collect();
×
708

NEW
709
                        match variant.data.kind {
×
710
                            StructKind::Unit => {
711
                                // Unit variant - nothing to deserialize
NEW
712
                                if !is_empty {
×
NEW
713
                                    self.skip_element(element_name)?;
×
NEW
714
                                }
×
715
                            }
716
                            StructKind::Tuple | StructKind::TupleStruct => {
717
                                // Tuple variant - deserialize fields by position
NEW
718
                                if !is_empty {
×
NEW
719
                                    partial = self.deserialize_tuple_content(
×
NEW
720
                                        partial,
×
NEW
721
                                        variant_fields,
×
NEW
722
                                        element_name,
×
NEW
723
                                    )?;
×
NEW
724
                                }
×
NEW
725
                                partial =
×
NEW
726
                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
727
                            }
728
                            StructKind::Struct => {
729
                                // Struct variant - deserialize as struct
NEW
730
                                partial = self.deserialize_attributes(
×
NEW
731
                                    partial,
×
NEW
732
                                    variant_fields,
×
NEW
733
                                    &other_attrs,
×
734
                                    false,
NEW
735
                                    span,
×
NEW
736
                                )?;
×
NEW
737
                                if !is_empty {
×
NEW
738
                                    partial = self.deserialize_element_content(
×
NEW
739
                                        partial,
×
NEW
740
                                        variant_fields,
×
NEW
741
                                        element_name,
×
742
                                        false,
NEW
743
                                    )?;
×
NEW
744
                                }
×
NEW
745
                                partial =
×
NEW
746
                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
747
                            }
748
                        }
749
                    }
750

NEW
751
                    return Ok(partial);
×
752
                }
13✔
753

754
                // Externally tagged (default) - two modes:
755
                // 1. Element name IS a variant name: <VariantName attr="...">...</VariantName>
756
                // 2. Element is a wrapper: <Wrapper><VariantName>...</VariantName></Wrapper>
757

758
                // Check if element name matches a variant's display name
759
                if let Some(variant) = enum_def
13✔
760
                    .variants
13✔
761
                    .iter()
13✔
762
                    .find(|v| get_variant_display_name(v) == element_name)
25✔
763
                {
764
                    // Mode 1: The element itself is the variant
765
                    // Use the original variant name for selection
766
                    partial = partial.select_variant_named(variant.name)?;
13✔
767
                    let variant_fields = variant.data.fields;
13✔
768

769
                    match variant.data.kind {
13✔
770
                        StructKind::Unit => {
771
                            // Unit variant - nothing to deserialize
NEW
772
                            if !is_empty {
×
NEW
773
                                self.skip_element(element_name)?;
×
NEW
774
                            }
×
775
                        }
776
                        StructKind::Tuple | StructKind::TupleStruct => {
777
                            // Tuple variant - check for newtype pattern
778
                            if variant_fields.len() == 1 {
13✔
779
                                // Newtype variant - deserialize inner value from current element
780
                                partial = partial.begin_nth_field(0)?;
13✔
781
                                partial = self.deserialize_element(
13✔
782
                                    partial,
13✔
783
                                    element_name,
13✔
784
                                    attributes,
13✔
785
                                    span,
13✔
786
                                    is_empty,
13✔
NEW
787
                                )?;
×
788
                                partial = partial.end()?;
13✔
NEW
789
                            } else if !is_empty {
×
790
                                // Multi-field tuple - deserialize from child elements
NEW
791
                                partial = self.deserialize_tuple_content(
×
NEW
792
                                    partial,
×
NEW
793
                                    variant_fields,
×
NEW
794
                                    element_name,
×
NEW
795
                                )?;
×
NEW
796
                                partial =
×
NEW
797
                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
798
                            } else {
NEW
799
                                partial =
×
NEW
800
                                    self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
801
                            }
802
                        }
803
                        StructKind::Struct => {
804
                            // Struct variant - deserialize attributes and content
NEW
805
                            partial = self.deserialize_attributes(
×
NEW
806
                                partial,
×
NEW
807
                                variant_fields,
×
NEW
808
                                attributes,
×
809
                                false,
NEW
810
                                span,
×
NEW
811
                            )?;
×
NEW
812
                            if !is_empty {
×
NEW
813
                                partial = self.deserialize_element_content(
×
NEW
814
                                    partial,
×
NEW
815
                                    variant_fields,
×
NEW
816
                                    element_name,
×
817
                                    false,
NEW
818
                                )?;
×
NEW
819
                            }
×
NEW
820
                            partial =
×
NEW
821
                                self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
822
                        }
823
                    }
824

825
                    return Ok(partial);
13✔
NEW
826
                }
×
827

828
                // Mode 2: Element is a wrapper containing the variant element
NEW
829
                if is_empty {
×
NEW
830
                    return Err(self.err_at(
×
NEW
831
                        XmlErrorKind::InvalidValueForShape(
×
NEW
832
                            "empty element for externally tagged enum".into(),
×
NEW
833
                        ),
×
NEW
834
                        span,
×
NEW
835
                    ));
×
NEW
836
                }
×
837

838
                // Read the variant element
NEW
839
                let variant_event = loop {
×
NEW
840
                    let Some(event) = self.next() else {
×
NEW
841
                        return Err(self.err(XmlErrorKind::UnexpectedEof));
×
842
                    };
843

NEW
844
                    match &event.event {
×
NEW
845
                        OwnedEvent::Text { content } if content.trim().is_empty() => {
×
846
                            // Skip whitespace
NEW
847
                            continue;
×
848
                        }
849
                        OwnedEvent::Start { .. } | OwnedEvent::Empty { .. } => {
NEW
850
                            break event;
×
851
                        }
852
                        _ => {
NEW
853
                            return Err(self.err_at(
×
NEW
854
                                XmlErrorKind::UnexpectedEvent(format!(
×
NEW
855
                                    "expected variant element, got {:?}",
×
NEW
856
                                    event.event
×
NEW
857
                                )),
×
NEW
858
                                event.span(),
×
NEW
859
                            ));
×
860
                        }
861
                    }
862
                };
863

NEW
864
                let variant_span = variant_event.span();
×
NEW
865
                let (variant_name, variant_attrs, variant_is_empty) = match &variant_event.event {
×
NEW
866
                    OwnedEvent::Start { name, attributes } => {
×
NEW
867
                        (name.clone(), attributes.clone(), false)
×
868
                    }
NEW
869
                    OwnedEvent::Empty { name, attributes } => {
×
NEW
870
                        (name.clone(), attributes.clone(), true)
×
871
                    }
NEW
872
                    _ => unreachable!(),
×
873
                };
874

875
                // Find the variant by display name (considering rename)
NEW
876
                let variant = enum_def
×
NEW
877
                    .variants
×
NEW
878
                    .iter()
×
NEW
879
                    .find(|v| get_variant_display_name(v) == variant_name)
×
NEW
880
                    .ok_or_else(|| {
×
NEW
881
                        self.err_at(
×
NEW
882
                            XmlErrorKind::NoMatchingElement(variant_name.clone()),
×
NEW
883
                            variant_span,
×
884
                        )
NEW
885
                    })?;
×
886

887
                // Select the variant using its original name
NEW
888
                partial = partial.select_variant_named(variant.name)?;
×
889

NEW
890
                let variant_fields = variant.data.fields;
×
891

NEW
892
                match variant.data.kind {
×
893
                    StructKind::Unit => {
894
                        // Unit variant - nothing to deserialize
NEW
895
                        if !variant_is_empty {
×
NEW
896
                            self.skip_element(&variant_name)?;
×
NEW
897
                        }
×
898
                    }
899
                    StructKind::Tuple | StructKind::TupleStruct => {
900
                        // Tuple variant - deserialize fields by position
NEW
901
                        if !variant_is_empty {
×
NEW
902
                            partial = self.deserialize_tuple_content(
×
NEW
903
                                partial,
×
NEW
904
                                variant_fields,
×
NEW
905
                                &variant_name,
×
NEW
906
                            )?;
×
NEW
907
                        }
×
NEW
908
                        partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
909
                    }
910
                    StructKind::Struct => {
911
                        // Struct variant - deserialize as struct
NEW
912
                        partial = self.deserialize_attributes(
×
NEW
913
                            partial,
×
NEW
914
                            variant_fields,
×
NEW
915
                            &variant_attrs,
×
916
                            false,
NEW
917
                            variant_span,
×
NEW
918
                        )?;
×
NEW
919
                        if !variant_is_empty {
×
NEW
920
                            partial = self.deserialize_element_content(
×
NEW
921
                                partial,
×
NEW
922
                                variant_fields,
×
NEW
923
                                &variant_name,
×
924
                                false,
NEW
925
                            )?;
×
NEW
926
                        }
×
NEW
927
                        partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
928
                    }
929
                }
930

931
                // Skip to the end of the wrapper element
932
                loop {
NEW
933
                    let Some(event) = self.next() else {
×
NEW
934
                        return Err(self.err(XmlErrorKind::UnexpectedEof));
×
935
                    };
936

NEW
937
                    match &event.event {
×
NEW
938
                        OwnedEvent::End { name } if name == element_name => {
×
NEW
939
                            break;
×
940
                        }
NEW
941
                        OwnedEvent::Text { content } if content.trim().is_empty() => {
×
942
                            // Skip whitespace
NEW
943
                            continue;
×
944
                        }
945
                        _ => {
NEW
946
                            return Err(self.err_at(
×
NEW
947
                                XmlErrorKind::UnexpectedEvent(format!(
×
NEW
948
                                    "expected end of enum wrapper, got {:?}",
×
NEW
949
                                    event.event
×
NEW
950
                                )),
×
NEW
951
                                event.span(),
×
NEW
952
                            ));
×
953
                        }
954
                    }
955
                }
956

NEW
957
                Ok(partial)
×
958
            }
NEW
959
            _ => Err(self.err_at(
×
NEW
960
                XmlErrorKind::UnsupportedShape(format!("cannot deserialize into {:?}", shape.ty)),
×
NEW
961
                span,
×
NEW
962
            )),
×
963
        }
964
    }
132✔
965

966
    /// Deserialize XML attributes into struct fields.
967
    fn deserialize_attributes<'facet>(
63✔
968
        &mut self,
63✔
969
        partial: Partial<'facet>,
63✔
970
        fields: &[Field],
63✔
971
        attributes: &[(String, String)],
63✔
972
        deny_unknown: bool,
63✔
973
        element_span: SourceSpan,
63✔
974
    ) -> Result<Partial<'facet>> {
63✔
975
        let mut partial = partial;
63✔
976

977
        for (attr_name, attr_value) in attributes {
83✔
978
            // Find the field that matches this attribute
979
            let field_match = fields
83✔
980
                .iter()
83✔
981
                .enumerate()
83✔
982
                .find(|(_, f)| f.is_xml_attribute() && f.name == attr_name);
147✔
983

984
            if let Some((idx, field)) = field_match {
83✔
985
                log::trace!(
83✔
986
                    "deserialize attribute {} into field {}",
987
                    attr_name,
988
                    field.name
989
                );
990

991
                partial = partial.begin_nth_field(idx)?;
83✔
992

993
                // Handle Option<T>
994
                let is_option = matches!(&partial.shape().def, Def::Option(_));
83✔
995
                if is_option {
83✔
996
                    partial = partial.begin_some()?;
52✔
997
                }
31✔
998

999
                // Handle Spanned<T>
1000
                if is_spanned_shape(partial.shape()) {
83✔
NEW
1001
                    partial = partial.begin_field("value")?;
×
1002
                }
83✔
1003

1004
                // Check if field has custom deserialization
1005
                let has_custom_deser = field.proxy_convert_in_fn().is_some();
83✔
1006
                if has_custom_deser {
83✔
NEW
1007
                    partial = partial.begin_custom_deserialization()?;
×
1008
                }
83✔
1009

1010
                // Deserialize the value
1011
                partial = self.set_scalar_value(partial, attr_value)?;
83✔
1012

1013
                // End custom deserialization if used (calls the conversion function)
1014
                if has_custom_deser {
83✔
NEW
1015
                    partial = partial.end()?;
×
1016
                }
83✔
1017

1018
                // End Spanned<T> if needed
1019
                if is_spanned_shape((field.shape)()) {
83✔
NEW
1020
                    partial = partial.end()?; // end value field
×
1021
                }
83✔
1022

1023
                // End Option<T> if needed
1024
                if is_option {
83✔
1025
                    partial = partial.end()?; // end Some
52✔
1026
                }
31✔
1027

1028
                partial = partial.end()?; // end field
83✔
NEW
1029
            } else if deny_unknown {
×
1030
                // Unknown attribute when deny_unknown_fields is set
NEW
1031
                let expected: Vec<&'static str> = fields
×
NEW
1032
                    .iter()
×
NEW
1033
                    .filter(|f| f.is_xml_attribute())
×
NEW
1034
                    .map(|f| f.name)
×
NEW
1035
                    .collect();
×
NEW
1036
                return Err(self.err_at(
×
NEW
1037
                    XmlErrorKind::UnknownAttribute {
×
NEW
1038
                        attribute: attr_name.clone(),
×
NEW
1039
                        expected,
×
NEW
1040
                    },
×
NEW
1041
                    element_span,
×
NEW
1042
                ));
×
NEW
1043
            }
×
1044
            // Otherwise ignore unknown attributes
1045
        }
1046

1047
        Ok(partial)
63✔
1048
    }
63✔
1049

1050
    /// Deserialize child elements and text content.
1051
    fn deserialize_element_content<'facet>(
41✔
1052
        &mut self,
41✔
1053
        partial: Partial<'facet>,
41✔
1054
        fields: &[Field],
41✔
1055
        parent_element_name: &str,
41✔
1056
        deny_unknown: bool,
41✔
1057
    ) -> Result<Partial<'facet>> {
41✔
1058
        let mut partial = partial;
41✔
1059
        let mut text_content = String::new();
41✔
1060

1061
        // Track which element fields are lists (for xml::elements)
1062
        let mut elements_field_started: Option<usize> = None;
41✔
1063

1064
        loop {
1065
            let Some(event) = self.next() else {
146✔
NEW
1066
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1067
            };
1068

1069
            let span = event.span();
146✔
1070

1071
            match event.event {
41✔
1072
                OwnedEvent::End { ref name } if name == parent_element_name => {
41✔
1073
                    // End any open elements list field
1074
                    // Note: begin_list() doesn't push a frame, so we only end the field
1075
                    if elements_field_started.is_some() {
41✔
1076
                        partial = partial.end()?; // end the elements field
16✔
1077
                    }
25✔
1078

1079
                    // Handle accumulated text content
1080
                    if !text_content.is_empty() {
41✔
1081
                        partial = self.set_text_field(partial, fields, &text_content)?;
4✔
1082
                    }
37✔
1083

1084
                    break;
41✔
1085
                }
1086
                OwnedEvent::Start { name, attributes } => {
83✔
1087
                    partial = self.deserialize_child_element(
83✔
1088
                        partial,
83✔
1089
                        fields,
83✔
1090
                        &name,
83✔
1091
                        &attributes,
83✔
1092
                        span,
83✔
1093
                        false,
1094
                        &mut elements_field_started,
83✔
1095
                        deny_unknown,
83✔
NEW
1096
                    )?;
×
1097
                }
1098
                OwnedEvent::Empty { name, attributes } => {
18✔
1099
                    partial = self.deserialize_child_element(
18✔
1100
                        partial,
18✔
1101
                        fields,
18✔
1102
                        &name,
18✔
1103
                        &attributes,
18✔
1104
                        span,
18✔
1105
                        true,
1106
                        &mut elements_field_started,
18✔
1107
                        deny_unknown,
18✔
NEW
1108
                    )?;
×
1109
                }
1110
                OwnedEvent::Text { content } | OwnedEvent::CData { content } => {
4✔
1111
                    text_content.push_str(&content);
4✔
1112
                }
4✔
NEW
1113
                OwnedEvent::End { name } => {
×
1114
                    // End tag for a different element - this shouldn't happen
NEW
1115
                    return Err(self.err_at(
×
NEW
1116
                        XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1117
                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
×
NEW
1118
                        )),
×
NEW
1119
                        span,
×
NEW
1120
                    ));
×
1121
                }
1122
                OwnedEvent::Eof => {
NEW
1123
                    return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1124
                }
1125
            }
1126
        }
1127

1128
        Ok(partial)
41✔
1129
    }
41✔
1130

1131
    /// Deserialize tuple struct content - fields are numbered elements like `<_0>`, `<_1>`, etc.
NEW
1132
    fn deserialize_tuple_content<'facet>(
×
NEW
1133
        &mut self,
×
NEW
1134
        partial: Partial<'facet>,
×
NEW
1135
        fields: &[Field],
×
NEW
1136
        parent_element_name: &str,
×
NEW
1137
    ) -> Result<Partial<'facet>> {
×
NEW
1138
        let mut partial = partial;
×
NEW
1139
        let mut field_idx = 0;
×
1140

1141
        loop {
NEW
1142
            let Some(event) = self.next() else {
×
NEW
1143
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1144
            };
1145

NEW
1146
            let span = event.span();
×
1147

NEW
1148
            match event.event {
×
NEW
1149
                OwnedEvent::End { ref name } if name == parent_element_name => {
×
NEW
1150
                    break;
×
1151
                }
NEW
1152
                OwnedEvent::Start { name, attributes } => {
×
NEW
1153
                    if field_idx >= fields.len() {
×
NEW
1154
                        return Err(self.err_at(
×
NEW
1155
                            XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1156
                                "too many elements for tuple struct (expected {})",
×
NEW
1157
                                fields.len()
×
NEW
1158
                            )),
×
NEW
1159
                            span,
×
NEW
1160
                        ));
×
NEW
1161
                    }
×
1162

NEW
1163
                    partial = partial.begin_nth_field(field_idx)?;
×
1164

1165
                    // Handle Option<T>
NEW
1166
                    let is_option = matches!(&partial.shape().def, Def::Option(_));
×
NEW
1167
                    if is_option {
×
NEW
1168
                        partial = partial.begin_some()?;
×
NEW
1169
                    }
×
1170

NEW
1171
                    partial = self.deserialize_element(partial, &name, &attributes, span, false)?;
×
NEW
1172
                    if is_option {
×
NEW
1173
                        partial = partial.end()?; // end Some
×
NEW
1174
                    }
×
NEW
1175
                    partial = partial.end()?; // end field
×
NEW
1176
                    field_idx += 1;
×
1177
                }
NEW
1178
                OwnedEvent::Empty { name, attributes } => {
×
NEW
1179
                    if field_idx >= fields.len() {
×
NEW
1180
                        return Err(self.err_at(
×
NEW
1181
                            XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1182
                                "too many elements for tuple struct (expected {})",
×
NEW
1183
                                fields.len()
×
NEW
1184
                            )),
×
NEW
1185
                            span,
×
NEW
1186
                        ));
×
NEW
1187
                    }
×
1188

NEW
1189
                    partial = partial.begin_nth_field(field_idx)?;
×
1190

1191
                    // Handle Option<T>
NEW
1192
                    let is_option = matches!(&partial.shape().def, Def::Option(_));
×
NEW
1193
                    if is_option {
×
NEW
1194
                        partial = partial.begin_some()?;
×
NEW
1195
                    }
×
1196

NEW
1197
                    partial = self.deserialize_element(partial, &name, &attributes, span, true)?;
×
NEW
1198
                    if is_option {
×
NEW
1199
                        partial = partial.end()?; // end Some
×
NEW
1200
                    }
×
NEW
1201
                    partial = partial.end()?; // end field
×
NEW
1202
                    field_idx += 1;
×
1203
                }
NEW
1204
                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
×
NEW
1205
                    // Ignore text content in tuple structs
×
NEW
1206
                }
×
NEW
1207
                OwnedEvent::End { name } => {
×
NEW
1208
                    return Err(self.err_at(
×
NEW
1209
                        XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1210
                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
×
NEW
1211
                        )),
×
NEW
1212
                        span,
×
NEW
1213
                    ));
×
1214
                }
1215
                OwnedEvent::Eof => {
NEW
1216
                    return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1217
                }
1218
            }
1219
        }
1220

NEW
1221
        Ok(partial)
×
NEW
1222
    }
×
1223

1224
    /// Deserialize fixed array content - expects sequential child elements
NEW
1225
    fn deserialize_array_content<'facet>(
×
NEW
1226
        &mut self,
×
NEW
1227
        partial: Partial<'facet>,
×
NEW
1228
        array_len: usize,
×
NEW
1229
        parent_element_name: &str,
×
NEW
1230
    ) -> Result<Partial<'facet>> {
×
NEW
1231
        let mut partial = partial;
×
NEW
1232
        let mut idx = 0;
×
1233

1234
        loop {
NEW
1235
            let Some(event) = self.next() else {
×
NEW
1236
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1237
            };
1238

NEW
1239
            let span = event.span();
×
1240

NEW
1241
            match event.event {
×
NEW
1242
                OwnedEvent::End { ref name } if name == parent_element_name => {
×
NEW
1243
                    if idx < array_len {
×
NEW
1244
                        return Err(self.err_at(
×
NEW
1245
                            XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1246
                                "not enough elements for array (got {idx}, expected {array_len})"
×
NEW
1247
                            )),
×
NEW
1248
                            span,
×
NEW
1249
                        ));
×
NEW
1250
                    }
×
NEW
1251
                    break;
×
1252
                }
NEW
1253
                OwnedEvent::Start { name, attributes } => {
×
NEW
1254
                    if idx >= array_len {
×
NEW
1255
                        return Err(self.err_at(
×
NEW
1256
                            XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1257
                                "too many elements for array (expected {array_len})"
×
NEW
1258
                            )),
×
NEW
1259
                            span,
×
NEW
1260
                        ));
×
NEW
1261
                    }
×
NEW
1262
                    partial = partial.begin_nth_field(idx)?;
×
NEW
1263
                    partial = self.deserialize_element(partial, &name, &attributes, span, false)?;
×
NEW
1264
                    partial = partial.end()?;
×
NEW
1265
                    idx += 1;
×
1266
                }
NEW
1267
                OwnedEvent::Empty { name, attributes } => {
×
NEW
1268
                    if idx >= array_len {
×
NEW
1269
                        return Err(self.err_at(
×
NEW
1270
                            XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1271
                                "too many elements for array (expected {array_len})"
×
NEW
1272
                            )),
×
NEW
1273
                            span,
×
NEW
1274
                        ));
×
NEW
1275
                    }
×
NEW
1276
                    partial = partial.begin_nth_field(idx)?;
×
NEW
1277
                    partial = self.deserialize_element(partial, &name, &attributes, span, true)?;
×
NEW
1278
                    partial = partial.end()?;
×
NEW
1279
                    idx += 1;
×
1280
                }
NEW
1281
                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
×
NEW
1282
                    // Ignore whitespace between elements
×
NEW
1283
                }
×
NEW
1284
                OwnedEvent::End { name } => {
×
NEW
1285
                    return Err(self.err_at(
×
NEW
1286
                        XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1287
                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
×
NEW
1288
                        )),
×
NEW
1289
                        span,
×
NEW
1290
                    ));
×
1291
                }
1292
                OwnedEvent::Eof => {
NEW
1293
                    return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1294
                }
1295
            }
1296
        }
1297

NEW
1298
        Ok(partial)
×
NEW
1299
    }
×
1300

1301
    /// Deserialize set content - each child element is a set item
NEW
1302
    fn deserialize_set_content<'facet>(
×
NEW
1303
        &mut self,
×
NEW
1304
        partial: Partial<'facet>,
×
NEW
1305
        parent_element_name: &str,
×
NEW
1306
    ) -> Result<Partial<'facet>> {
×
NEW
1307
        let mut partial = partial;
×
NEW
1308
        partial = partial.begin_set()?;
×
1309

1310
        loop {
NEW
1311
            let Some(event) = self.next() else {
×
NEW
1312
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1313
            };
1314

NEW
1315
            let span = event.span();
×
1316

NEW
1317
            match event.event {
×
NEW
1318
                OwnedEvent::End { ref name } if name == parent_element_name => {
×
NEW
1319
                    break;
×
1320
                }
NEW
1321
                OwnedEvent::Start { name, attributes } => {
×
NEW
1322
                    partial = partial.begin_set_item()?;
×
NEW
1323
                    partial = self.deserialize_element(partial, &name, &attributes, span, false)?;
×
NEW
1324
                    partial = partial.end()?; // end set item
×
1325
                }
NEW
1326
                OwnedEvent::Empty { name, attributes } => {
×
NEW
1327
                    partial = partial.begin_set_item()?;
×
NEW
1328
                    partial = self.deserialize_element(partial, &name, &attributes, span, true)?;
×
NEW
1329
                    partial = partial.end()?; // end set item
×
1330
                }
NEW
1331
                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
×
NEW
1332
                    // Ignore whitespace between elements
×
NEW
1333
                }
×
NEW
1334
                OwnedEvent::End { name } => {
×
NEW
1335
                    return Err(self.err_at(
×
NEW
1336
                        XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1337
                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
×
NEW
1338
                        )),
×
NEW
1339
                        span,
×
NEW
1340
                    ));
×
1341
                }
1342
                OwnedEvent::Eof => {
NEW
1343
                    return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1344
                }
1345
            }
1346
        }
1347

NEW
1348
        Ok(partial)
×
NEW
1349
    }
×
1350

1351
    /// Deserialize map content - expects <entry key="...">value</entry> or similar structure
NEW
1352
    fn deserialize_map_content<'facet>(
×
NEW
1353
        &mut self,
×
NEW
1354
        partial: Partial<'facet>,
×
NEW
1355
        parent_element_name: &str,
×
NEW
1356
    ) -> Result<Partial<'facet>> {
×
NEW
1357
        let mut partial = partial;
×
NEW
1358
        partial = partial.begin_map()?;
×
1359

1360
        loop {
NEW
1361
            let Some(event) = self.next() else {
×
NEW
1362
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1363
            };
1364

NEW
1365
            let span = event.span();
×
1366

NEW
1367
            match event.event {
×
NEW
1368
                OwnedEvent::End { ref name } if name == parent_element_name => {
×
NEW
1369
                    break;
×
1370
                }
NEW
1371
                OwnedEvent::Start { name, attributes } => {
×
1372
                    // Map entry: element name is the key, content is the value
NEW
1373
                    partial = partial.begin_key()?;
×
NEW
1374
                    partial = partial.set(name.clone())?;
×
NEW
1375
                    partial = partial.end()?; // end key
×
1376

NEW
1377
                    partial = partial.begin_value()?;
×
1378
                    // If there's a key attribute, use that as context; otherwise read content
NEW
1379
                    partial = self.deserialize_map_entry_value(partial, &name, &attributes)?;
×
NEW
1380
                    partial = partial.end()?; // end value
×
1381
                }
NEW
1382
                OwnedEvent::Empty { name, .. } => {
×
1383
                    // Empty element as map entry - key is element name, value is default/empty
NEW
1384
                    partial = partial.begin_key()?;
×
NEW
1385
                    partial = partial.set(name.clone())?;
×
NEW
1386
                    partial = partial.end()?; // end key
×
1387

NEW
1388
                    partial = partial.begin_value()?;
×
1389
                    // Set default value for the map value type
NEW
1390
                    let value_shape = partial.shape();
×
NEW
1391
                    if value_shape.is_type::<String>() {
×
NEW
1392
                        partial = partial.set(String::new())?;
×
NEW
1393
                    } else if value_shape.is_type::<bool>() {
×
NEW
1394
                        partial = partial.set(true)?; // presence implies true
×
1395
                    } else {
NEW
1396
                        return Err(self.err_at(
×
NEW
1397
                            XmlErrorKind::InvalidValueForShape(
×
NEW
1398
                                "empty element for non-string/bool map value".into(),
×
NEW
1399
                            ),
×
NEW
1400
                            span,
×
NEW
1401
                        ));
×
1402
                    }
NEW
1403
                    partial = partial.end()?; // end value
×
1404
                }
NEW
1405
                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {
×
NEW
1406
                    // Ignore whitespace between elements
×
NEW
1407
                }
×
NEW
1408
                OwnedEvent::End { name } => {
×
NEW
1409
                    return Err(self.err_at(
×
NEW
1410
                        XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1411
                            "unexpected end tag for '{name}' while parsing '{parent_element_name}'"
×
NEW
1412
                        )),
×
NEW
1413
                        span,
×
NEW
1414
                    ));
×
1415
                }
1416
                OwnedEvent::Eof => {
NEW
1417
                    return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1418
                }
1419
            }
1420
        }
1421

NEW
1422
        Ok(partial)
×
NEW
1423
    }
×
1424

1425
    /// Deserialize the value portion of a map entry
NEW
1426
    fn deserialize_map_entry_value<'facet>(
×
NEW
1427
        &mut self,
×
NEW
1428
        partial: Partial<'facet>,
×
NEW
1429
        element_name: &str,
×
NEW
1430
        _attributes: &[(String, String)],
×
NEW
1431
    ) -> Result<Partial<'facet>> {
×
NEW
1432
        let mut partial = partial;
×
NEW
1433
        let shape = partial.shape();
×
1434

1435
        // For scalar values, read text content
NEW
1436
        if matches!(&shape.def, Def::Scalar) {
×
NEW
1437
            let text = self.read_text_until_end(element_name)?;
×
NEW
1438
            partial = self.set_scalar_value(partial, &text)?;
×
NEW
1439
            return Ok(partial);
×
NEW
1440
        }
×
1441

1442
        // For complex values, read the element content
1443
        // This is a simplified version - complex map values would need more work
NEW
1444
        let text = self.read_text_until_end(element_name)?;
×
NEW
1445
        if shape.is_type::<String>() {
×
NEW
1446
            partial = partial.set(text)?;
×
1447
        } else {
NEW
1448
            partial = self.set_scalar_value(partial, &text)?;
×
1449
        }
1450

NEW
1451
        Ok(partial)
×
NEW
1452
    }
×
1453

1454
    /// Deserialize a child element into the appropriate field.
1455
    #[allow(clippy::too_many_arguments)]
1456
    fn deserialize_child_element<'facet>(
101✔
1457
        &mut self,
101✔
1458
        partial: Partial<'facet>,
101✔
1459
        fields: &[Field],
101✔
1460
        element_name: &str,
101✔
1461
        attributes: &[(String, String)],
101✔
1462
        span: SourceSpan,
101✔
1463
        is_empty: bool,
101✔
1464
        elements_field_started: &mut Option<usize>,
101✔
1465
        deny_unknown: bool,
101✔
1466
    ) -> Result<Partial<'facet>> {
101✔
1467
        let mut partial = partial;
101✔
1468

1469
        // First try to find a direct element field match
1470
        if let Some((idx, field)) = fields
101✔
1471
            .iter()
101✔
1472
            .enumerate()
101✔
1473
            .find(|(_, f)| f.is_xml_element() && f.name == element_name)
288✔
1474
        {
1475
            log::trace!("matched element {} to field {}", element_name, field.name);
65✔
1476

1477
            // End any open elements list field
1478
            // Note: begin_list() doesn't push a frame, so we only end the field
1479
            if elements_field_started.is_some() {
65✔
1480
                partial = partial.end()?; // end previous field
1✔
1481
                *elements_field_started = None;
1✔
1482
            }
64✔
1483

1484
            partial = partial.begin_nth_field(idx)?;
65✔
1485

1486
            // Handle Option<T>
1487
            let is_option = matches!(&partial.shape().def, Def::Option(_));
65✔
1488
            if is_option {
65✔
1489
                partial = partial.begin_some()?;
35✔
1490
            }
30✔
1491

1492
            // Check if field has custom deserialization
1493
            let has_custom_deser = field.proxy_convert_in_fn().is_some();
65✔
1494
            if has_custom_deser {
65✔
NEW
1495
                partial = partial.begin_custom_deserialization()?;
×
1496
            }
65✔
1497

1498
            // Deserialize the element content
1499
            partial =
65✔
1500
                self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
65✔
1501

1502
            // End custom deserialization if used (calls the conversion function)
1503
            if has_custom_deser {
65✔
NEW
1504
                partial = partial.end()?;
×
1505
            }
65✔
1506

1507
            // End Option<T> if needed
1508
            if is_option {
65✔
1509
                partial = partial.end()?; // end Some
35✔
1510
            }
30✔
1511

1512
            partial = partial.end()?; // end field
65✔
1513
            return Ok(partial);
65✔
1514
        }
36✔
1515

1516
        // Try to find an elements (list) field that accepts this element
1517
        // We check: 1) if the item type accepts this element name, or
1518
        //           2) if the field name matches the element name (fallback)
1519
        if let Some((idx, _field)) = fields.iter().enumerate().find(|(_, f)| {
98✔
1520
            if !f.is_xml_elements() {
98✔
1521
                return false;
60✔
1522
            }
38✔
1523
            // First, check if field name matches element name (common case for Vec<T>)
1524
            if get_field_display_name(f) == element_name {
38✔
1525
                return true;
24✔
1526
            }
14✔
1527
            // Otherwise, check if the list item type accepts this element
1528
            let field_shape = (f.shape)();
14✔
1529
            if let Some(item_shape) = get_list_item_shape(field_shape) {
14✔
1530
                shape_accepts_element(item_shape, element_name)
14✔
1531
            } else {
1532
                // Not a list type - shouldn't happen for xml::elements
NEW
1533
                false
×
1534
            }
1535
        }) {
98✔
1536
            // If we haven't started this list yet, begin it
1537
            if elements_field_started.is_none() || *elements_field_started != Some(idx) {
36✔
1538
                // End previous list field if any
1539
                // Note: begin_list() doesn't push a frame, so we only end the field
1540
                if elements_field_started.is_some() {
19✔
1541
                    partial = partial.end()?; // end previous field
2✔
1542
                }
17✔
1543

1544
                partial = partial.begin_nth_field(idx)?;
19✔
1545
                partial = partial.begin_list()?;
19✔
1546
                *elements_field_started = Some(idx);
19✔
1547
            }
17✔
1548

1549
            // Add item to list
1550
            partial = partial.begin_list_item()?;
36✔
1551
            partial =
36✔
1552
                self.deserialize_element(partial, element_name, attributes, span, is_empty)?;
36✔
1553
            partial = partial.end()?; // end list item
36✔
1554

1555
            return Ok(partial);
36✔
NEW
1556
        }
×
1557

1558
        // No matching field found
NEW
1559
        if deny_unknown {
×
1560
            // Unknown element when deny_unknown_fields is set
NEW
1561
            let expected: Vec<&'static str> = fields
×
NEW
1562
                .iter()
×
NEW
1563
                .filter(|f| f.is_xml_element() || f.is_xml_elements())
×
NEW
1564
                .map(|f| f.name)
×
NEW
1565
                .collect();
×
NEW
1566
            return Err(self.err_at(
×
NEW
1567
                XmlErrorKind::UnknownField {
×
NEW
1568
                    field: element_name.to_string(),
×
NEW
1569
                    expected,
×
NEW
1570
                },
×
NEW
1571
                span,
×
NEW
1572
            ));
×
NEW
1573
        }
×
1574

1575
        // Skip this element
NEW
1576
        log::trace!("skipping unknown element: {element_name}");
×
NEW
1577
        if !is_empty {
×
NEW
1578
            self.skip_element(element_name)?;
×
NEW
1579
        }
×
NEW
1580
        Ok(partial)
×
1581
    }
101✔
1582

1583
    /// Set the text content field.
1584
    fn set_text_field<'facet>(
4✔
1585
        &mut self,
4✔
1586
        partial: Partial<'facet>,
4✔
1587
        fields: &[Field],
4✔
1588
        text: &str,
4✔
1589
    ) -> Result<Partial<'facet>> {
4✔
1590
        let mut partial = partial;
4✔
1591

1592
        // Find the text field
1593
        if let Some((idx, _field)) = fields.iter().enumerate().find(|(_, f)| f.is_xml_text()) {
11✔
1594
            partial = partial.begin_nth_field(idx)?;
4✔
1595

1596
            // Handle Option<T>
1597
            let is_option = matches!(&partial.shape().def, Def::Option(_));
4✔
1598
            if is_option {
4✔
NEW
1599
                partial = partial.begin_some()?;
×
1600
            }
4✔
1601

1602
            partial = partial.set(text.to_string())?;
4✔
1603

1604
            // End Option<T> if needed
1605
            if is_option {
4✔
NEW
1606
                partial = partial.end()?; // end Some
×
1607
            }
4✔
1608

1609
            partial = partial.end()?; // end field
4✔
NEW
1610
        }
×
1611
        // If no text field, ignore the text content
1612

1613
        Ok(partial)
4✔
1614
    }
4✔
1615

1616
    /// Read text content until the end tag.
1617
    fn read_text_until_end(&mut self, element_name: &str) -> Result<String> {
56✔
1618
        let mut text = String::new();
56✔
1619

1620
        loop {
1621
            let Some(event) = self.next() else {
112✔
NEW
1622
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1623
            };
1624

1625
            match event.event {
56✔
1626
                OwnedEvent::End { ref name } if name == element_name => {
56✔
1627
                    break;
56✔
1628
                }
1629
                OwnedEvent::Text { content } | OwnedEvent::CData { content } => {
56✔
1630
                    text.push_str(&content);
56✔
1631
                }
56✔
NEW
1632
                other => {
×
NEW
1633
                    return Err(self.err(XmlErrorKind::UnexpectedEvent(format!(
×
NEW
1634
                        "expected text or end tag, got {other:?}"
×
NEW
1635
                    ))));
×
1636
                }
1637
            }
1638
        }
1639

1640
        Ok(text)
56✔
1641
    }
56✔
1642

1643
    /// Skip an element and all its content.
NEW
1644
    fn skip_element(&mut self, element_name: &str) -> Result<()> {
×
NEW
1645
        let mut depth = 1;
×
1646

NEW
1647
        while depth > 0 {
×
NEW
1648
            let Some(event) = self.next() else {
×
NEW
1649
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1650
            };
1651

NEW
1652
            match &event.event {
×
NEW
1653
                OwnedEvent::Start { .. } => depth += 1,
×
NEW
1654
                OwnedEvent::End { name } if name == element_name && depth == 1 => {
×
NEW
1655
                    depth -= 1;
×
NEW
1656
                }
×
NEW
1657
                OwnedEvent::End { .. } => depth -= 1,
×
NEW
1658
                OwnedEvent::Empty { .. } => {}
×
NEW
1659
                OwnedEvent::Text { .. } | OwnedEvent::CData { .. } => {}
×
NEW
1660
                OwnedEvent::Eof => return Err(self.err(XmlErrorKind::UnexpectedEof)),
×
1661
            }
1662
        }
1663

NEW
1664
        Ok(())
×
NEW
1665
    }
×
1666

1667
    /// Set defaults for any unset fields.
1668
    fn set_defaults_for_unset_fields<'facet>(
63✔
1669
        &self,
63✔
1670
        partial: Partial<'facet>,
63✔
1671
        fields: &[Field],
63✔
1672
    ) -> Result<Partial<'facet>> {
63✔
1673
        use facet_core::Characteristic;
1674
        let mut partial = partial;
63✔
1675

1676
        for (idx, field) in fields.iter().enumerate() {
201✔
1677
            if partial.is_field_set(idx)? {
201✔
1678
                continue;
171✔
1679
            }
30✔
1680

1681
            let field_has_default_flag = field.has_default();
30✔
1682
            let field_has_default_fn = field.default_fn().is_some();
30✔
1683
            let field_type_has_default = (field.shape)().is(Characteristic::Default);
30✔
1684
            let should_skip = field.should_skip_deserializing();
30✔
1685

1686
            if field_has_default_fn
30✔
1687
                || field_has_default_flag
30✔
1688
                || field_type_has_default
1✔
NEW
1689
                || should_skip
×
1690
            {
1691
                log::trace!("setting default for unset field: {}", field.name);
30✔
1692
                partial = partial.set_nth_field_to_default(idx)?;
30✔
NEW
1693
            }
×
1694
        }
1695

1696
        Ok(partial)
63✔
1697
    }
63✔
1698

1699
    /// Set a scalar value on the partial based on its type.
1700
    fn set_scalar_value<'facet>(
139✔
1701
        &self,
139✔
1702
        partial: Partial<'facet>,
139✔
1703
        value: &str,
139✔
1704
    ) -> Result<Partial<'facet>> {
139✔
1705
        let mut partial = partial;
139✔
1706
        let shape = partial.shape();
139✔
1707

1708
        // Handle transparent wrappers
1709
        if shape.inner.is_some() {
139✔
NEW
1710
            partial = partial.begin_inner()?;
×
NEW
1711
            partial = self.set_scalar_value(partial, value)?;
×
NEW
1712
            partial = partial.end()?;
×
NEW
1713
            return Ok(partial);
×
1714
        }
139✔
1715

1716
        // Handle usize and isize explicitly before other numeric types
1717
        if shape.is_type::<usize>() {
139✔
NEW
1718
            let n: usize = value.parse().map_err(|_| {
×
NEW
1719
                self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1720
                    "cannot parse `{value}` as usize"
×
NEW
1721
                )))
×
NEW
1722
            })?;
×
NEW
1723
            partial = partial.set(n)?;
×
NEW
1724
            return Ok(partial);
×
1725
        }
139✔
1726

1727
        if shape.is_type::<isize>() {
139✔
NEW
1728
            let n: isize = value.parse().map_err(|_| {
×
NEW
1729
                self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1730
                    "cannot parse `{value}` as isize"
×
NEW
1731
                )))
×
NEW
1732
            })?;
×
NEW
1733
            partial = partial.set(n)?;
×
NEW
1734
            return Ok(partial);
×
1735
        }
139✔
1736

1737
        // Try numeric types
1738
        if let Type::Primitive(PrimitiveType::Numeric(numeric_type)) = shape.ty {
3✔
1739
            let size = match shape.layout {
3✔
1740
                ShapeLayout::Sized(layout) => layout.size(),
3✔
1741
                ShapeLayout::Unsized => {
NEW
1742
                    return Err(self.err(XmlErrorKind::InvalidValueForShape(
×
NEW
1743
                        "cannot assign to unsized type".into(),
×
NEW
1744
                    )));
×
1745
                }
1746
            };
1747

1748
            return self.set_numeric_value(partial, value, numeric_type, size);
3✔
1749
        }
136✔
1750

1751
        // Boolean
1752
        if shape.is_type::<bool>() {
136✔
NEW
1753
            let b = match value.to_lowercase().as_str() {
×
NEW
1754
                "true" | "1" | "yes" => true,
×
NEW
1755
                "false" | "0" | "no" => false,
×
1756
                _ => {
NEW
1757
                    return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1758
                        "cannot parse `{value}` as boolean"
×
NEW
1759
                    ))));
×
1760
                }
1761
            };
NEW
1762
            partial = partial.set(b)?;
×
NEW
1763
            return Ok(partial);
×
1764
        }
136✔
1765

1766
        // Char
1767
        if shape.is_type::<char>() {
136✔
NEW
1768
            let mut chars = value.chars();
×
NEW
1769
            let c = chars.next().ok_or_else(|| {
×
NEW
1770
                self.err(XmlErrorKind::InvalidValueForShape(
×
NEW
1771
                    "empty string cannot be converted to char".into(),
×
NEW
1772
                ))
×
NEW
1773
            })?;
×
NEW
1774
            if chars.next().is_some() {
×
NEW
1775
                return Err(self.err(XmlErrorKind::InvalidValueForShape(
×
NEW
1776
                    "string has more than one character".into(),
×
NEW
1777
                )));
×
NEW
1778
            }
×
NEW
1779
            partial = partial.set(c)?;
×
NEW
1780
            return Ok(partial);
×
1781
        }
136✔
1782

1783
        // String
1784
        if shape.is_type::<String>() {
136✔
1785
            partial = partial.set(value.to_string())?;
136✔
1786
            return Ok(partial);
136✔
NEW
1787
        }
×
1788

1789
        // Try parse_from_str for other types (IpAddr, DateTime, etc.)
NEW
1790
        if partial.shape().vtable.parse.is_some() {
×
NEW
1791
            partial = partial
×
NEW
1792
                .parse_from_str(value)
×
NEW
1793
                .map_err(|e| self.err(XmlErrorKind::Reflect(e)))?;
×
NEW
1794
            return Ok(partial);
×
NEW
1795
        }
×
1796

1797
        // Last resort: try setting as string
NEW
1798
        partial = partial
×
NEW
1799
            .set(value.to_string())
×
NEW
1800
            .map_err(|e| self.err(XmlErrorKind::Reflect(e)))?;
×
1801

NEW
1802
        Ok(partial)
×
1803
    }
139✔
1804

1805
    /// Set a numeric value with proper type conversion.
1806
    fn set_numeric_value<'facet>(
3✔
1807
        &self,
3✔
1808
        partial: Partial<'facet>,
3✔
1809
        value: &str,
3✔
1810
        numeric_type: NumericType,
3✔
1811
        size: usize,
3✔
1812
    ) -> Result<Partial<'facet>> {
3✔
1813
        let mut partial = partial;
3✔
1814
        match numeric_type {
3✔
1815
            NumericType::Integer { signed: false } => {
1816
                let n: u64 = value.parse().map_err(|_| {
3✔
NEW
1817
                    self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1818
                        "cannot parse `{value}` as unsigned integer"
×
NEW
1819
                    )))
×
NEW
1820
                })?;
×
1821

1822
                match size {
3✔
1823
                    1 => {
NEW
1824
                        let v = u8::try_from(n).map_err(|_| {
×
NEW
1825
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1826
                                "`{value}` out of range for u8"
×
NEW
1827
                            )))
×
NEW
1828
                        })?;
×
NEW
1829
                        partial = partial.set(v)?;
×
1830
                    }
1831
                    2 => {
NEW
1832
                        let v = u16::try_from(n).map_err(|_| {
×
NEW
1833
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1834
                                "`{value}` out of range for u16"
×
NEW
1835
                            )))
×
NEW
1836
                        })?;
×
NEW
1837
                        partial = partial.set(v)?;
×
1838
                    }
1839
                    4 => {
1840
                        let v = u32::try_from(n).map_err(|_| {
3✔
NEW
1841
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1842
                                "`{value}` out of range for u32"
×
NEW
1843
                            )))
×
NEW
1844
                        })?;
×
1845
                        partial = partial.set(v)?;
3✔
1846
                    }
1847
                    8 => {
NEW
1848
                        partial = partial.set(n)?;
×
1849
                    }
1850
                    16 => {
NEW
1851
                        let n: u128 = value.parse().map_err(|_| {
×
NEW
1852
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1853
                                "cannot parse `{value}` as u128"
×
NEW
1854
                            )))
×
NEW
1855
                        })?;
×
NEW
1856
                        partial = partial.set(n)?;
×
1857
                    }
1858
                    _ => {
NEW
1859
                        return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1860
                            "unsupported unsigned integer size: {size}"
×
NEW
1861
                        ))));
×
1862
                    }
1863
                }
1864
            }
1865
            NumericType::Integer { signed: true } => {
NEW
1866
                let n: i64 = value.parse().map_err(|_| {
×
NEW
1867
                    self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1868
                        "cannot parse `{value}` as signed integer"
×
NEW
1869
                    )))
×
NEW
1870
                })?;
×
1871

NEW
1872
                match size {
×
1873
                    1 => {
NEW
1874
                        let v = i8::try_from(n).map_err(|_| {
×
NEW
1875
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1876
                                "`{value}` out of range for i8"
×
NEW
1877
                            )))
×
NEW
1878
                        })?;
×
NEW
1879
                        partial = partial.set(v)?;
×
1880
                    }
1881
                    2 => {
NEW
1882
                        let v = i16::try_from(n).map_err(|_| {
×
NEW
1883
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1884
                                "`{value}` out of range for i16"
×
NEW
1885
                            )))
×
NEW
1886
                        })?;
×
NEW
1887
                        partial = partial.set(v)?;
×
1888
                    }
1889
                    4 => {
NEW
1890
                        let v = i32::try_from(n).map_err(|_| {
×
NEW
1891
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1892
                                "`{value}` out of range for i32"
×
NEW
1893
                            )))
×
NEW
1894
                        })?;
×
NEW
1895
                        partial = partial.set(v)?;
×
1896
                    }
1897
                    8 => {
NEW
1898
                        partial = partial.set(n)?;
×
1899
                    }
1900
                    16 => {
NEW
1901
                        let n: i128 = value.parse().map_err(|_| {
×
NEW
1902
                            self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1903
                                "cannot parse `{value}` as i128"
×
NEW
1904
                            )))
×
NEW
1905
                        })?;
×
NEW
1906
                        partial = partial.set(n)?;
×
1907
                    }
1908
                    _ => {
NEW
1909
                        return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1910
                            "unsupported signed integer size: {size}"
×
NEW
1911
                        ))));
×
1912
                    }
1913
                }
1914
            }
NEW
1915
            NumericType::Float => match size {
×
1916
                4 => {
NEW
1917
                    let v: f32 = value.parse().map_err(|_| {
×
NEW
1918
                        self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1919
                            "cannot parse `{value}` as f32"
×
NEW
1920
                        )))
×
NEW
1921
                    })?;
×
NEW
1922
                    partial = partial.set(v)?;
×
1923
                }
1924
                8 => {
NEW
1925
                    let v: f64 = value.parse().map_err(|_| {
×
NEW
1926
                        self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1927
                            "cannot parse `{value}` as f64"
×
NEW
1928
                        )))
×
NEW
1929
                    })?;
×
NEW
1930
                    partial = partial.set(v)?;
×
1931
                }
1932
                _ => {
NEW
1933
                    return Err(self.err(XmlErrorKind::InvalidValueForShape(format!(
×
NEW
1934
                        "unsupported float size: {size}"
×
NEW
1935
                    ))));
×
1936
                }
1937
            },
1938
        }
1939

1940
        Ok(partial)
3✔
1941
    }
3✔
1942

1943
    /// Deserialize adjacently tagged enum content.
1944
    /// Format: <Element tag="Variant"><content>...</content></Element>
NEW
1945
    fn deserialize_adjacently_tagged_content<'facet>(
×
NEW
1946
        &mut self,
×
NEW
1947
        partial: Partial<'facet>,
×
NEW
1948
        variant: &Variant,
×
NEW
1949
        content_tag: &str,
×
NEW
1950
        parent_element_name: &str,
×
NEW
1951
    ) -> Result<Partial<'facet>> {
×
NEW
1952
        let mut partial = partial;
×
NEW
1953
        let variant_fields = variant.data.fields;
×
1954

1955
        loop {
NEW
1956
            let Some(event) = self.next() else {
×
NEW
1957
                return Err(self.err(XmlErrorKind::UnexpectedEof));
×
1958
            };
1959

NEW
1960
            let span = event.span();
×
1961

NEW
1962
            match event.event {
×
NEW
1963
                OwnedEvent::End { ref name } if name == parent_element_name => {
×
1964
                    // End of wrapper - set defaults for unset fields
NEW
1965
                    partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
NEW
1966
                    break;
×
1967
                }
1968
                OwnedEvent::Start {
NEW
1969
                    ref name,
×
NEW
1970
                    ref attributes,
×
NEW
1971
                } if name == content_tag => {
×
1972
                    // Found content element - deserialize based on variant kind
NEW
1973
                    match variant.data.kind {
×
1974
                        StructKind::Unit => {
1975
                            // Unit variant - skip content
NEW
1976
                            self.skip_element(name)?;
×
1977
                        }
1978
                        StructKind::Tuple | StructKind::TupleStruct => {
NEW
1979
                            partial =
×
NEW
1980
                                self.deserialize_tuple_content(partial, variant_fields, name)?;
×
1981
                        }
1982
                        StructKind::Struct => {
NEW
1983
                            partial = self.deserialize_attributes(
×
NEW
1984
                                partial,
×
NEW
1985
                                variant_fields,
×
NEW
1986
                                attributes,
×
1987
                                false,
NEW
1988
                                span,
×
NEW
1989
                            )?;
×
NEW
1990
                            partial = self.deserialize_element_content(
×
NEW
1991
                                partial,
×
NEW
1992
                                variant_fields,
×
NEW
1993
                                name,
×
1994
                                false,
NEW
1995
                            )?;
×
1996
                        }
1997
                    }
NEW
1998
                    partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
1999
                }
2000
                OwnedEvent::Empty {
NEW
2001
                    ref name,
×
NEW
2002
                    ref attributes,
×
NEW
2003
                } if name == content_tag => {
×
2004
                    // Empty content element
NEW
2005
                    match variant.data.kind {
×
NEW
2006
                        StructKind::Unit => {}
×
2007
                        StructKind::Struct => {
NEW
2008
                            partial = self.deserialize_attributes(
×
NEW
2009
                                partial,
×
NEW
2010
                                variant_fields,
×
NEW
2011
                                attributes,
×
2012
                                false,
NEW
2013
                                span,
×
NEW
2014
                            )?;
×
2015
                        }
NEW
2016
                        _ => {}
×
2017
                    }
NEW
2018
                    partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
2019
                }
NEW
2020
                OwnedEvent::Text { ref content } if content.trim().is_empty() => {
×
2021
                    // Skip whitespace
NEW
2022
                    continue;
×
2023
                }
2024
                _ => {
NEW
2025
                    return Err(self.err_at(
×
NEW
2026
                        XmlErrorKind::UnexpectedEvent(format!(
×
NEW
2027
                            "expected content element <{}>, got {:?}",
×
NEW
2028
                            content_tag, event.event
×
NEW
2029
                        )),
×
NEW
2030
                        span,
×
NEW
2031
                    ));
×
2032
                }
2033
            }
2034
        }
2035

NEW
2036
        Ok(partial)
×
NEW
2037
    }
×
2038

2039
    /// Deserialize untagged enum - try each variant until one succeeds.
NEW
2040
    fn deserialize_untagged_enum<'facet>(
×
NEW
2041
        &mut self,
×
NEW
2042
        partial: Partial<'facet>,
×
NEW
2043
        enum_type: &EnumType,
×
NEW
2044
        element_name: &str,
×
NEW
2045
        attributes: &[(String, String)],
×
NEW
2046
        span: SourceSpan,
×
NEW
2047
        is_empty: bool,
×
NEW
2048
    ) -> Result<Partial<'facet>> {
×
2049
        // For untagged enums, we need to try each variant
2050
        // This is tricky because we can't easily "rewind" the partial
2051
        // For now, we'll use a simple heuristic based on available fields
2052

2053
        // Collect child element names to help determine variant
NEW
2054
        let saved_pos = self.pos;
×
2055

2056
        // For untagged enums, try variants in order
NEW
2057
        for variant in enum_type.variants.iter() {
×
2058
            // Try to match this variant
NEW
2059
            self.pos = saved_pos; // Reset position for each attempt
×
2060

2061
            // Allocate a fresh partial for this attempt
NEW
2062
            let attempt_partial = Partial::alloc_shape(partial.shape())?;
×
NEW
2063
            let attempt_partial = attempt_partial.select_variant_named(variant.name)?;
×
2064

2065
            // Try to deserialize into this variant
NEW
2066
            let result = self.try_deserialize_variant(
×
NEW
2067
                attempt_partial,
×
NEW
2068
                variant,
×
NEW
2069
                element_name,
×
NEW
2070
                attributes,
×
NEW
2071
                span,
×
NEW
2072
                is_empty,
×
2073
            );
2074

NEW
2075
            if result.is_ok() {
×
2076
                // Successfully matched - return this partial
2077
                // But we need to transfer the data to the original partial
2078
                // This is complex with the current API, so we return the new one
NEW
2079
                return result;
×
NEW
2080
            }
×
2081
        }
2082

2083
        // No variant matched
NEW
2084
        Err(self.err_at(
×
NEW
2085
            XmlErrorKind::InvalidValueForShape("no variant matched for untagged enum".to_string()),
×
NEW
2086
            span,
×
NEW
2087
        ))
×
NEW
2088
    }
×
2089

2090
    /// Try to deserialize a specific variant.
NEW
2091
    fn try_deserialize_variant<'facet>(
×
NEW
2092
        &mut self,
×
NEW
2093
        partial: Partial<'facet>,
×
NEW
2094
        variant: &Variant,
×
NEW
2095
        element_name: &str,
×
NEW
2096
        attributes: &[(String, String)],
×
NEW
2097
        span: SourceSpan,
×
NEW
2098
        is_empty: bool,
×
NEW
2099
    ) -> Result<Partial<'facet>> {
×
NEW
2100
        let mut partial = partial;
×
NEW
2101
        let variant_fields = variant.data.fields;
×
2102

NEW
2103
        match variant.data.kind {
×
2104
            StructKind::Unit => {
2105
                // Unit variant - nothing to deserialize
NEW
2106
                if !is_empty {
×
NEW
2107
                    self.skip_element(element_name)?;
×
NEW
2108
                }
×
2109
            }
2110
            StructKind::Tuple | StructKind::TupleStruct => {
NEW
2111
                if !is_empty {
×
NEW
2112
                    partial =
×
NEW
2113
                        self.deserialize_tuple_content(partial, variant_fields, element_name)?;
×
NEW
2114
                }
×
NEW
2115
                partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
2116
            }
2117
            StructKind::Struct => {
NEW
2118
                partial =
×
NEW
2119
                    self.deserialize_attributes(partial, variant_fields, attributes, false, span)?;
×
NEW
2120
                if !is_empty {
×
NEW
2121
                    partial = self.deserialize_element_content(
×
NEW
2122
                        partial,
×
NEW
2123
                        variant_fields,
×
NEW
2124
                        element_name,
×
2125
                        false,
NEW
2126
                    )?;
×
NEW
2127
                }
×
NEW
2128
                partial = self.set_defaults_for_unset_fields(partial, variant_fields)?;
×
2129
            }
2130
        }
2131

NEW
2132
        Ok(partial)
×
NEW
2133
    }
×
2134

2135
    /// Check if a struct has any flattened fields.
2136
    fn has_flatten_fields(struct_def: &StructType) -> bool {
63✔
2137
        struct_def.fields.iter().any(|f| f.is_flattened())
201✔
2138
    }
63✔
2139

2140
    /// Deserialize a struct with flattened fields using facet-solver.
2141
    ///
2142
    /// This uses a two-pass approach:
2143
    /// 1. Peek mode: Scan all element names and attributes, feed to solver
2144
    /// 2. Deserialize: Use the resolved Configuration to deserialize with proper path handling
NEW
2145
    fn deserialize_struct_with_flatten<'facet>(
×
NEW
2146
        &mut self,
×
NEW
2147
        partial: Partial<'facet>,
×
NEW
2148
        struct_def: &StructType,
×
NEW
2149
        element_name: &str,
×
NEW
2150
        attributes: &[(String, String)],
×
NEW
2151
        span: SourceSpan,
×
NEW
2152
        is_empty: bool,
×
NEW
2153
    ) -> Result<Partial<'facet>> {
×
NEW
2154
        let mut partial = partial;
×
2155

NEW
2156
        log::trace!(
×
2157
            "deserialize_struct_with_flatten: {}",
NEW
2158
            partial.shape().type_identifier
×
2159
        );
2160

2161
        // Build the schema for this type
NEW
2162
        let schema = Schema::build_auto(partial.shape())
×
NEW
2163
            .map_err(|e| self.err_at(XmlErrorKind::SchemaError(e), span))?;
×
2164

2165
        // Create the solver
NEW
2166
        let mut solver = Solver::new(&schema);
×
2167

2168
        // Feed attribute names to solver
NEW
2169
        for (attr_name, _) in attributes {
×
NEW
2170
            let key_static: &'static str = Box::leak(attr_name.clone().into_boxed_str());
×
NEW
2171
            let _decision = solver.see_key(key_static);
×
NEW
2172
        }
×
2173

2174
        // Track child element positions for pass 2
NEW
2175
        let mut element_positions: Vec<(&'static str, usize)> = Vec::new();
×
NEW
2176
        let saved_pos = self.pos;
×
2177

2178
        // ========== PASS 1: Peek mode - scan all child elements ==========
NEW
2179
        if !is_empty {
×
2180
            loop {
NEW
2181
                let Some(event) = self.next() else {
×
NEW
2182
                    return Err(self.err(XmlErrorKind::UnexpectedEof));
×
2183
                };
2184

NEW
2185
                match &event.event {
×
NEW
2186
                    OwnedEvent::End { name } if name == element_name => {
×
NEW
2187
                        break;
×
2188
                    }
NEW
2189
                    OwnedEvent::Start { name, .. } | OwnedEvent::Empty { name, .. } => {
×
2190
                        // Record position before this element
NEW
2191
                        let elem_pos = self.pos - 1; // We already consumed this event
×
2192

2193
                        // Leak the name for 'static lifetime
NEW
2194
                        let key_static: &'static str = Box::leak(name.clone().into_boxed_str());
×
NEW
2195
                        let _decision = solver.see_key(key_static);
×
NEW
2196
                        element_positions.push((key_static, elem_pos));
×
2197

2198
                        // Skip the element content if it's a Start event
NEW
2199
                        if matches!(&event.event, OwnedEvent::Start { .. }) {
×
NEW
2200
                            self.skip_element(name)?;
×
NEW
2201
                        }
×
2202
                    }
NEW
2203
                    OwnedEvent::Text { content } if content.trim().is_empty() => {
×
2204
                        // Skip whitespace
NEW
2205
                        continue;
×
2206
                    }
2207
                    OwnedEvent::Text { .. } => {
2208
                        // Text content - might be for a text field
2209
                        // For now we skip it in the peek pass
NEW
2210
                        continue;
×
2211
                    }
2212
                    _ => {
NEW
2213
                        return Err(self.err_at(
×
NEW
2214
                            XmlErrorKind::UnexpectedEvent(format!(
×
NEW
2215
                                "expected element or end tag, got {:?}",
×
NEW
2216
                                event.event
×
NEW
2217
                            )),
×
NEW
2218
                            event.span(),
×
NEW
2219
                        ));
×
2220
                    }
2221
                }
2222
            }
NEW
2223
        }
×
2224

2225
        // ========== Get the resolved Configuration ==========
NEW
2226
        let config = solver
×
NEW
2227
            .finish()
×
NEW
2228
            .map_err(|e| self.err_at(XmlErrorKind::Solver(e), span))?;
×
2229

2230
        // ========== PASS 2: Deserialize with proper path handling ==========
2231

2232
        // First, handle attributes using the configuration
NEW
2233
        for (attr_name, attr_value) in attributes {
×
NEW
2234
            if let Some(field_info) = config.field(attr_name) {
×
NEW
2235
                let segments = field_info.path.segments();
×
2236

2237
                // Navigate to the field through the path, tracking Option fields
NEW
2238
                let mut option_count = 0;
×
NEW
2239
                for segment in segments {
×
NEW
2240
                    match segment {
×
NEW
2241
                        PathSegment::Field(name) => {
×
NEW
2242
                            partial = partial.begin_field(name)?;
×
2243
                            // Handle Option fields
NEW
2244
                            if matches!(partial.shape().def, Def::Option(_)) {
×
NEW
2245
                                partial = partial.begin_some()?;
×
NEW
2246
                                option_count += 1;
×
NEW
2247
                            }
×
2248
                        }
NEW
2249
                        PathSegment::Variant(_, variant_name) => {
×
NEW
2250
                            partial = partial.select_variant_named(variant_name)?;
×
2251
                        }
2252
                    }
2253
                }
2254

2255
                // Handle Spanned<T>
NEW
2256
                if is_spanned_shape(partial.shape()) {
×
NEW
2257
                    partial = partial.begin_field("value")?;
×
NEW
2258
                }
×
2259

2260
                // Deserialize the attribute value
NEW
2261
                partial = self.set_scalar_value(partial, attr_value)?;
×
2262

2263
                // Unwind: end Spanned if needed
NEW
2264
                if is_spanned_shape(partial.shape()) {
×
NEW
2265
                    partial = partial.end()?;
×
NEW
2266
                }
×
2267

2268
                // Unwind the path (including Option Some wrappers)
NEW
2269
                for _ in 0..option_count {
×
NEW
2270
                    partial = partial.end()?; // end Some
×
2271
                }
NEW
2272
                for segment in segments.iter().rev() {
×
NEW
2273
                    if matches!(segment, PathSegment::Field(_)) {
×
NEW
2274
                        partial = partial.end()?;
×
NEW
2275
                    }
×
2276
                }
NEW
2277
            }
×
2278
        }
2279

2280
        // Handle elements using the configuration
2281
        // Reset position to replay elements
NEW
2282
        self.pos = saved_pos;
×
2283

NEW
2284
        if !is_empty {
×
2285
            loop {
NEW
2286
                let Some(event) = self.next() else {
×
NEW
2287
                    return Err(self.err(XmlErrorKind::UnexpectedEof));
×
2288
                };
2289

NEW
2290
                let event_span = event.span();
×
2291

NEW
2292
                match event.event {
×
NEW
2293
                    OwnedEvent::End { ref name } if name == element_name => {
×
NEW
2294
                        break;
×
2295
                    }
2296
                    OwnedEvent::Start {
NEW
2297
                        ref name,
×
NEW
2298
                        ref attributes,
×
2299
                    }
2300
                    | OwnedEvent::Empty {
NEW
2301
                        ref name,
×
NEW
2302
                        ref attributes,
×
2303
                    } => {
NEW
2304
                        let is_elem_empty = matches!(event.event, OwnedEvent::Empty { .. });
×
2305

NEW
2306
                        if let Some(field_info) = config.field(name) {
×
NEW
2307
                            let segments = field_info.path.segments();
×
2308

2309
                            // Navigate to the field through the path, tracking Option fields
NEW
2310
                            let mut option_count = 0;
×
NEW
2311
                            for segment in segments {
×
NEW
2312
                                match segment {
×
NEW
2313
                                    PathSegment::Field(field_name) => {
×
NEW
2314
                                        partial = partial.begin_field(field_name)?;
×
2315
                                        // Handle Option fields
NEW
2316
                                        if matches!(partial.shape().def, Def::Option(_)) {
×
NEW
2317
                                            partial = partial.begin_some()?;
×
NEW
2318
                                            option_count += 1;
×
NEW
2319
                                        }
×
2320
                                    }
NEW
2321
                                    PathSegment::Variant(_, variant_name) => {
×
NEW
2322
                                        partial = partial.select_variant_named(variant_name)?;
×
2323
                                    }
2324
                                }
2325
                            }
2326

2327
                            // Deserialize the element
NEW
2328
                            partial = self.deserialize_element(
×
NEW
2329
                                partial,
×
NEW
2330
                                name,
×
NEW
2331
                                attributes,
×
NEW
2332
                                event_span,
×
NEW
2333
                                is_elem_empty,
×
NEW
2334
                            )?;
×
2335

2336
                            // Unwind the path (including Option Some wrappers)
NEW
2337
                            for _ in 0..option_count {
×
NEW
2338
                                partial = partial.end()?; // end Some
×
2339
                            }
NEW
2340
                            for segment in segments.iter().rev() {
×
NEW
2341
                                if matches!(segment, PathSegment::Field(_)) {
×
NEW
2342
                                    partial = partial.end()?;
×
NEW
2343
                                }
×
2344
                            }
2345
                        } else {
2346
                            // Unknown element - skip it
NEW
2347
                            if !is_elem_empty {
×
NEW
2348
                                self.skip_element(name)?;
×
NEW
2349
                            }
×
2350
                        }
2351
                    }
NEW
2352
                    OwnedEvent::Text { ref content } if content.trim().is_empty() => {
×
NEW
2353
                        continue;
×
2354
                    }
2355
                    OwnedEvent::Text { .. } => {
2356
                        // Text content - handle if there's a text field
2357
                        // For now skip
NEW
2358
                        continue;
×
2359
                    }
2360
                    _ => {
NEW
2361
                        return Err(self.err_at(
×
NEW
2362
                            XmlErrorKind::UnexpectedEvent(format!(
×
NEW
2363
                                "expected element or end tag, got {:?}",
×
NEW
2364
                                event.event
×
NEW
2365
                            )),
×
NEW
2366
                            event_span,
×
NEW
2367
                        ));
×
2368
                    }
2369
                }
2370
            }
NEW
2371
        }
×
2372

2373
        // Set defaults for any unset fields
NEW
2374
        partial = self.set_defaults_for_unset_fields(partial, struct_def.fields)?;
×
2375

NEW
2376
        Ok(partial)
×
NEW
2377
    }
×
2378
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc