1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::io::Read;

use serde::de;
use xml::reader::XmlEvent;

use crate::de::ChildDeserializer;
use crate::debug_expect;
use crate::error::{Error, Result};

pub struct SeqAccess<'a, R: Read> {
    de: ChildDeserializer<'a, R>,
    max_size: Option<usize>,
    seq_type: SeqType,
}

pub enum SeqType {
    /// Sequence is of elements with the same name.
    ByElementName {
        expected_name: String,
        search_non_contiguous: bool,
    },
    /// Sequence is of all elements/text at current depth.
    AllMembers,
}

impl<'a, R: 'a + Read> SeqAccess<'a, R> {
    pub fn new(mut de: ChildDeserializer<'a, R>, max_size: Option<usize>) -> Self {
        let seq_type = if de.unset_map_value() {
            debug_expect!(de.peek(), Ok(&XmlEvent::StartElement { ref name, .. }) => {
                SeqType::ByElementName {
                    expected_name: name.local_name.clone(),
                    search_non_contiguous: de.non_contiguous_seq_elements
                }
            })
        } else {
            SeqType::AllMembers
        };
        SeqAccess {
            de,
            max_size,
            seq_type,
        }
    }
}

impl<'de, 'a, R: 'a + Read> de::SeqAccess<'de> for SeqAccess<'a, R> {
    type Error = Error;

    fn next_element_seed<T: de::DeserializeSeed<'de>>(
        &mut self,
        seed: T,
    ) -> Result<Option<T::Value>> {
        match self.max_size.as_mut() {
            Some(&mut 0) => {
                return Ok(None);
            }
            Some(max_size) => {
                *max_size -= 1;
            }
            None => {}
        }

        match &self.seq_type {
            SeqType::ByElementName {
                expected_name,
                search_non_contiguous,
            } => {
                let mut local_depth = 0;

                loop {
                    let next_element = self.de.peek()?;

                    match next_element {
                        XmlEvent::StartElement { name, .. }
                            if &name.local_name == expected_name && local_depth == 0 =>
                        {
                            self.de.set_map_value();
                            return seed.deserialize(&mut self.de).map(Some);
                        }
                        XmlEvent::StartElement { .. } => {
                            if *search_non_contiguous {
                                self.de.buffered_reader.skip();
                                local_depth += 1;
                            } else {
                                return Ok(None);
                            }
                        }
                        XmlEvent::EndElement { .. } => {
                            if local_depth == 0 {
                                return Ok(None);
                            } else {
                                local_depth -= 1;
                                self.de.buffered_reader.skip();
                            }
                        }
                        XmlEvent::EndDocument => {
                            return Ok(None);
                        }
                        _ => {
                            self.de.buffered_reader.skip();
                        }
                    }
                }
            }
            SeqType::AllMembers => {
                let next_element = self.de.peek()?;

                match next_element {
                    XmlEvent::EndElement { .. } | XmlEvent::EndDocument => return Ok(None),
                    _ => {
                        return seed.deserialize(&mut self.de).map(Some);
                    }
                }
            }
        }
    }

    fn size_hint(&self) -> Option<usize> {
        self.max_size
    }
}