Amandasaurus
Amandasaurus

Reputation: 60709

Implementing an iterator on itself returned as a box - compile error about Iterator not impl'ed, despite being impl'ed

I am trying to write a library that will read bytes (e.g. from a file), and parse out objects and return an interator over them. However I am having trouble implementing the iterator, even with a dummy version.

Here is my code:

use std::io::Read;

// One of the objects I want to return
pub struct ObjA {
    data: i8,
}

// There might be other kinds of objects here.
pub enum MyObj {
    ObjA(ObjA),
}

// There will be other input formats, and I want a generic trait for "read bytes and return MyObj's"
pub trait ObjReader<R> {
    // This should create the parser/reader from a std::io::Read source
    fn new(R) -> Self;

    // This will iterate over the objects. (AFAIK this is how to return an iterator)
    fn objects(&self) -> Box<Iterator<Item=MyObj>>;
}

// The data will be in XML, so here's a stupid struct that will (eventually) parse it and return objects. It obv. takes a `Read`
pub struct XMLReader<R: Read> {
    inner_reader: R,
}

// The XMLReader will be an ObjReader
impl<R: Read> ObjReader<R> for XMLReader<R> {
    fn new(reader: R) -> XMLReader<R> {
        XMLReader { inner_reader: reader }
    }

    // Return the iterator for the objects, I'll keep it simple and iterate over itself, rather than create a new struct
    fn objects(&self) -> Box<Iterator<Item=MyObj>> {
        Box::new(self)
    }
}

// Make XMLReader be an iterator
impl<R: Read> Iterator for XMLReader<R> {
    type Item = MyObj;

    // Right now, it's always empty. This is a stub
    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

// Dummy main to allow it to compile
fn main() {

}

And I get this error:

$ multirust run beta rustc test.rs
test.rs:24:13: 24:27 error: the trait `core::iter::Iterator` is not implemented for the type `&XMLReader<R>` [E0277]
test.rs:24             Box::new(self)
                       ^~~~~~~~~~~~~~
test.rs:24:13: 24:27 help: run `rustc --explain E0277` to see a detailed explanation
test.rs:24:13: 24:27 note: `&XMLReader<R>` is not an iterator; maybe try calling `.iter()` or a similar method
test.rs:24:13: 24:27 note: required for the cast to the object type `core::iter::Iterator<Item=MyObj> + 'static`
error: aborting due to previous error

The error is how XMLReader doesn't iterate, but I have impl'ed Iterator for it. How can I make this work?

I am using rust 1.7 beta from multirust. (the stable rustc segfaulted on me....)

$ multirust run beta rustc --version
rustc 1.7.0-beta.4 (5ed7d4e31 2016-02-26)

Upvotes: 0

Views: 57

Answers (1)

Matthieu M.
Matthieu M.

Reputation: 299890

The answer is both simple and annoying: you have implemented Iterator for XMLReader<R> and not &XMLReader<R> OR you have to Box the value and not the reference.

The former will not get you far, because then you will be trying to create a Box around a reference... there are two possibilities:

  1. Have a different type for the reader and the iterator
  2. Change the signature of objects to take self by value

Then you will also have to take care to constrain R to ensure that it does not reference objects that could cease to live before you are done with your iteration. A 'static bound would be simpler to start with.

Upvotes: 2

Related Questions