I'm attempting to write an incremental XML parser in Rust using quick_xml.
Some of the XML files will not fit in memory (on my laptop) so I'm trying to only store relevant chunks of each file in a buffer of Vec<u8>.
Within each file chunk of Vec<u8> I want to store borrows to slices in some struct Data
quick_xml provides a read_event method which appends to the buffer and returns a quick_xml::events::Event (an enum containing a struct with a buf: Cow<'a, [u8]> field which borrows from the buffer)
Essentially I want to take the data referenced by the Event and store it in my Data struct.
However the borrow checker has a heart attack because the Event only lives for the call to read_event and I'm trying to keep a reference to it that lives as long as the data in the buffer.
The code below is the implementation of what I have tried to describe above. Could I get some help in storing a borrow to the underlying buf from an Event?
use quick_xml::events::Event;
use quick_xml::Reader;
const XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<RUN_SET xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RUN xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" alias="HAP1 gene trap unselected control dataset" accession="SRR2034585" center_name="Stanford University">
<IDENTIFIERS>
<PRIMARY_ID>SRR2034585</PRIMARY_ID>
<SUBMITTER_ID namespace="Stanford University">HAP1 gene trap unselected control dataset</SUBMITTER_ID>
</IDENTIFIERS>
<EXPERIMENT_REF accession="SRX1034759"/>
</RUN>
</RUN_SET>
"#;
#[derive(Debug)]
struct Data<'a> {
primary_id: Option<&'a [u8]>,
experiment_ref: Option<&'a [u8]>,
}
fn main() {
let mut buf: Vec<u8> = vec![];
let mut reader = Reader::from_str(XML);
let mut depth = 0;
let mut path: Vec<u8> = vec![];
reader.expand_empty_elements(true);
let mut data = Data { primary_id: None, experiment_ref: None };
loop {
match reader.read_event(&mut buf) {
Ok(Event::Start(ref e)) => {
depth += 1;
path.push(b"/"[0]);
path.append(&mut e.name().to_vec());
if path == "/RUN_SET/RUN/EXPERIMENT_REF".as_bytes() {
let experiment_ref = // What to put here?
data = Data { experiment_ref, ..data };
}
}
Ok(Event::End(ref e)) => {
depth -= 1;
path.truncate(path.len() - e.name().len() - 1);
}
Ok(Event::Eof) => { break; }
_ => {}
}
if depth == 1 {
println!("{:?}", data);
buf.clear();
path.clear();
}
}
}