1 use crate::debug_expect;
2 use crate::error::Result;
3 use std::{collections::VecDeque, io::Read};
4 use xml::reader::{EventReader, XmlEvent};
5 
6 /// Retrieve XML events from an underlying reader.
7 pub trait BufferedXmlReader<R: Read> {
8     /// Get and "consume" the next event.
next(&mut self) -> Result<XmlEvent>9     fn next(&mut self) -> Result<XmlEvent>;
10 
11     /// Get the next event without consuming.
peek(&mut self) -> Result<&XmlEvent>12     fn peek(&mut self) -> Result<&XmlEvent>;
13 
14     /// Spawn a child buffer whose cursor starts at the same position as this buffer.
child_buffer<'a>(&'a mut self) -> ChildXmlBuffer<'a, R>15     fn child_buffer<'a>(&'a mut self) -> ChildXmlBuffer<'a, R>;
16 }
17 
18 pub struct RootXmlBuffer<R: Read> {
19     reader: EventReader<R>,
20     buffer: VecDeque<CachedXmlEvent>,
21 }
22 
23 impl<R: Read> RootXmlBuffer<R> {
new(reader: EventReader<R>) -> Self24     pub fn new(reader: EventReader<R>) -> Self {
25         RootXmlBuffer {
26             reader,
27             buffer: VecDeque::new(),
28         }
29     }
30 }
31 
32 impl<R: Read> BufferedXmlReader<R> for RootXmlBuffer<R> {
33     /// Consumed XML events in the root buffer are moved to the caller
next(&mut self) -> Result<XmlEvent>34     fn next(&mut self) -> Result<XmlEvent> {
35         loop {
36             match self.buffer.pop_front() {
37                 Some(CachedXmlEvent::Unused(ev)) => break Ok(ev),
38                 Some(CachedXmlEvent::Used) => continue,
39                 None => break next_significant_event(&mut self.reader),
40             }
41         }
42     }
43 
peek(&mut self) -> Result<&XmlEvent>44     fn peek(&mut self) -> Result<&XmlEvent> {
45         get_from_buffer_or_reader(&mut self.buffer, &mut self.reader, &mut 0)
46     }
47 
child_buffer<'root>(&'root mut self) -> ChildXmlBuffer<'root, R>48     fn child_buffer<'root>(&'root mut self) -> ChildXmlBuffer<'root, R> {
49         let RootXmlBuffer { reader, buffer } = self;
50         ChildXmlBuffer {
51             reader,
52             buffer,
53             cursor: 0,
54         }
55     }
56 }
57 
58 pub struct ChildXmlBuffer<'parent, R: Read> {
59     reader: &'parent mut EventReader<R>,
60     buffer: &'parent mut VecDeque<CachedXmlEvent>,
61     cursor: usize,
62 }
63 
64 impl<'parent, R: Read> ChildXmlBuffer<'parent, R> {
65     /// Advance the child buffer without marking an event as "used"
skip(&mut self)66     pub fn skip(&mut self) {
67         debug_assert!(
68             self.cursor < self.buffer.len(),
69             ".skip() only should be called after .peek()"
70         );
71 
72         self.cursor += 1;
73     }
74 }
75 
76 impl<'parent, R: Read> BufferedXmlReader<R> for ChildXmlBuffer<'parent, R> {
77     /// Consumed XML events in a child buffer are marked as "used"
next(&mut self) -> Result<XmlEvent>78     fn next(&mut self) -> Result<XmlEvent> {
79         loop {
80             match self.buffer.get_mut(self.cursor) {
81                 Some(entry @ CachedXmlEvent::Unused(_)) => {
82                     let taken = if self.cursor == 0 {
83                         self.buffer.pop_front().unwrap()
84                     } else {
85                         std::mem::replace(entry, CachedXmlEvent::Used)
86                     };
87 
88                     return debug_expect!(taken, CachedXmlEvent::Unused(ev) => Ok(ev));
89                 }
90                 Some(CachedXmlEvent::Used) => {
91                     debug_assert!(
92                         self.cursor != 0,
93                         "Event buffer should not start with 'used' slot (should have been popped)"
94                     );
95                     self.cursor += 1;
96                     continue;
97                 }
98                 None => {
99                     debug_assert_eq!(self.buffer.len(), self.cursor);
100 
101                     // Skip creation of buffer entry when consuming event straight away
102                     return next_significant_event(&mut self.reader);
103                 }
104             }
105         }
106     }
107 
peek(&mut self) -> Result<&XmlEvent>108     fn peek(&mut self) -> Result<&XmlEvent> {
109         get_from_buffer_or_reader(self.buffer, self.reader, &mut self.cursor)
110     }
111 
child_buffer<'a>(&'a mut self) -> ChildXmlBuffer<'a, R>112     fn child_buffer<'a>(&'a mut self) -> ChildXmlBuffer<'a, R> {
113         let ChildXmlBuffer {
114             reader,
115             buffer,
116             cursor,
117         } = self;
118 
119         ChildXmlBuffer {
120             reader,
121             buffer,
122             cursor: *cursor,
123         }
124     }
125 }
126 
127 #[derive(Debug)]
128 enum CachedXmlEvent {
129     Unused(XmlEvent),
130     Used,
131 }
132 
get_from_buffer_or_reader<'buf>( buffer: &'buf mut VecDeque<CachedXmlEvent>, reader: &mut EventReader<impl Read>, index: &mut usize, ) -> Result<&'buf XmlEvent>133 fn get_from_buffer_or_reader<'buf>(
134     buffer: &'buf mut VecDeque<CachedXmlEvent>,
135     reader: &mut EventReader<impl Read>,
136     index: &mut usize,
137 ) -> Result<&'buf XmlEvent> {
138     // We should only be attempting to get an event already in the buffer, or the next event to place in the buffer
139     debug_assert!(*index <= buffer.len());
140 
141     loop {
142         match buffer.get_mut(*index) {
143             Some(CachedXmlEvent::Unused(_)) => break,
144             Some(CachedXmlEvent::Used) => {
145                 *index += 1;
146             }
147             None => {
148                 let next = next_significant_event(reader)?;
149                 buffer.push_back(CachedXmlEvent::Unused(next));
150             }
151         }
152     }
153 
154     // Returning of borrowed data must be done after of loop/match due to current limitation of borrow checker
155     debug_expect!(buffer.get_mut(*index), Some(CachedXmlEvent::Unused(event)) => Ok(event))
156 }
157 
158 /// Reads the next XML event from the underlying reader, skipping events we're not interested in.
next_significant_event(reader: &mut EventReader<impl Read>) -> Result<XmlEvent>159 fn next_significant_event(reader: &mut EventReader<impl Read>) -> Result<XmlEvent> {
160     loop {
161         match reader.next()? {
162             XmlEvent::StartDocument { .. }
163             | XmlEvent::ProcessingInstruction { .. }
164             | XmlEvent::Whitespace { .. }
165             | XmlEvent::Comment(_) => { /* skip */ }
166             other => return Ok(other),
167         }
168     }
169 }
170