New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
panick on read_namespaced_event with different buffers #125
Comments
I notice now that this is probably the same as #107. |
Sorry I haven't answered. Yes it is the same issue (not using the same buffer). |
I am not completely convinced you want to stop people doing this. I have come back to after a while because it really does stop me building a recursive parser straight-forwardly and a parser with a single loop becomes unreadable rapidly. So, it seems a intuitive thing to want to do. Is there not an easier way of supporting this usage, either with methods that do not require access to the internal buffers, or creation of Events that do not share ownership? |
I have some time now. I'll work on it. |
To give an example of the sort of thing I am trying to achieve, But this breaks. The mutable borrow of As always, my rust is very limited, but I have been around the houses I realise that this is extending the bug report beyond it's current extern crate quick_xml;
use quick_xml::events::Event;
use quick_xml::Reader;
use std::io::BufRead;
struct Read<R>
where
R: BufRead,
{
reader: Reader<R>,
}
impl<R: BufRead> Read<R> {
fn new(reader: Reader<R>) -> Read<R> {
Read {
reader: reader,
buf: Vec::new(),
ns_buf: Vec::new()
}
}
fn parse(&mut self) {
loop {
let mut e = self.reader.read_namespaced_event(&mut self.buf,
&mut self.ns_buf);
match e {
Ok ((ref ns, Event::Start(ref mut e)))
if *ns == Some(b"http://www.example.com") => {
match e.local_name() {
b"Fred" => {
self.parse_fred();
}
_ => {}
}
}
_ => {}
}
}
}
fn parse_fred(&mut self) {
loop {
let mut e = self.reader.read_namespaced_event(&mut self.buf,
&mut self.ns_buf);
match e {
Ok ((ref ns, Event::Start(ref mut e)))
if *ns == Some(b"http://www.example.com") => {
match e.local_name() {
b"George" => {
println!("George Inside Fred");
}
_ => {}
}
}
_ => {}
}
}
}
} |
After considerable trial and error, I think I have managed to get a It's fairly hairy but at least it works. This could be cleaned up with It involves a lot of copying also, which seems inefficient, but I @willempx I am curious. Your original example is pathological and meant as a reproduction rather than useful. What were you trying to do when you got the bug in the first place? extern crate quick_xml;
use quick_xml::events::Event;
use quick_xml::Reader;
use std::io::BufRead;
pub struct Read<R>
where
R: BufRead,
{
reader: Reader<R>,
buf: Vec<u8>,
ns_buf: Vec<u8>
}
impl<R: BufRead> Read<R> {
pub fn new(reader: Reader<R>) -> Read<R> {
Read {
reader: reader,
buf: Vec::new(),
ns_buf: Vec::new()
}
}
pub fn parse(&mut self) {
loop {
let mut e;
{
let e_inner = self.reader.read_event(&mut self.buf);
match e_inner {
Ok(e_inner_inner) => {
e = e_inner_inner.into_owned();
}
Err(_) => {
panic!("Panic");
}
}
}
match e {
Event::Start(ref mut e) => {
match e.local_name() {
b"Fred" => {
self.parse_fred();
}
_ => {}
}
}
_ => {}
}
}
}
fn parse_fred(&mut self) {
loop {
let mut e = self.reader.read_event(&mut self.buf);
match e {
Ok (Event::Start(ref mut e)) => {
match e.local_name() {
b"George" => {
println!("George Inside Fred");
}
_ => {}
}
}
_ => {}
}
}
}
pub fn parse_ns(&mut self) {
loop {
let e;
let o;
{
let e_inner = self.reader.read_namespaced_event(&mut self.buf,
&mut self.ns_buf
);
match e_inner {
Ok((option, e_inner_inner)) => {
e = e_inner_inner.into_owned();
o = option.unwrap().to_owned();
}
Err(_) => {
panic!("Panic");
}
}
}
match (o, e) {
(_, Event::Start(ref mut e)) => {
match e.local_name() {
b"Fred" => {
self.parse_ns_fred();
}
_ => {}
}
}
_ => {}
}
}
}
fn parse_ns_fred(&mut self) {
loop {
let mut e = self.reader.read_event(&mut self.buf);
match e {
Ok (Event::Start(ref mut e)) => {
match e.local_name() {
b"George" => {
println!("George Inside Fred");
}
_ => {}
}
}
_ => {}
}
}
}
} |
Ok so let me try answering. The core part of this issue will probably be fixed naturally once NLL lands on rust compiler, so I don't think fixing this is particularly urgent (needs to be confirmed tough). Your issue is very similar with issues you may have when working with Here is a workaround (showing only the fn parse(&mut self) {
enum State {
ParseFred,
Ignore,
}
loop {
let state = {
let e = self.reader.read_namespaced_event(&mut self.buf,
&mut self.ns_buf);
match e {
Ok ((ref ns, Event::Start(ref e))) if *ns == Some(b"http://www.example.com") => {
match e.local_name() {
b"Fred" => State::ParseFred,
_ => State::Ignore,
}
}
_ => State::Ignore,
}
};
match state {
State::ParseFred => self.parse_fred(),
State::Ignore => {},
}
}
} |
I think I was in a similar scenario as you in #107 : it was a function that parsed an XML and called helper functions to parse parts (e.g. the But I was just playing around as a rust beginner (which I still am); do not take what I was doing as advice or a good example. The bug report was just about the apparent mismatch between API specification and implementation (no precondition written in the specification, but still a crash in the implementation). |
@tafia True enough. I think I will use my solution (of copying), which I should be able to back out cleanly and replace with NLL hit stable. I've got a state enum at the moment -- it something I was hoping to get rid of with some functions! Thanks for all the explanations, especially as my issues are a little tangential to the bug. |
Just to update on this. I have tried this with NLL on nightly and indeed the example I gave in #125 (comment) does indeed compile fine without complaints (I tried this in July, but Unfortunately, since I wrote originally, I've changed my code organisation and it simply raises other ownership issues. I'll see whether I can resolve these, but for the moment, I have partial success, but no working code! |
I'm hit by this bug too. I'm parsing a very complicated XML file and one loop does not suffice. This is minimal code that panics: fn main() {
let content = "<a:a xmlns:a='urn:a'></a:a>";
let mut r = quick_xml::Reader::from_reader(content.as_bytes());
let mut buf = Vec::new();
let mut ns_buf = Vec::new();
r.read_namespaced_event(&mut buf, &mut ns_buf).unwrap();
r.read_namespaced_event(&mut buf, &mut ns_buf).unwrap();
r.read_namespaced_event(&mut buf, &mut ns_buf).unwrap();
// use different namespace buffer for closing tag
let mut ns_buf = Vec::new();
r.read_namespaced_event(&mut buf, &mut ns_buf).unwrap();
} Here is my use-case. I'm stuck when parsing xml with quick-xml. The challenge is handling ownership with the function An element may have two series of child elements, e.g. an optional element First there is a loop to read |
Feel free to share examples of code not working. Thanks for the heads up. |
Duplicate of #59 |
Environment: Debian 9 amd64
Reproducibility: Always
Version: quick_xml 0.12.1. Also known to be reproducible with 0.11.0.
Steps to reproduce: compile and run this:
Acutal result: it panics:
Expected result:
The text was updated successfully, but these errors were encountered: