Is it possible to create an iterator for ZipArchive in zip crate?


#1

Hi guys, I’m super new to rust (like since Thursday) so please bear with me :slight_smile:

As an exercise, I’d like to implement Iterator for ZipArchive using fn by_index<'a>(&'a mut self, file_number: usize) -> ZipResult< ZipFile<'a> > in order to iterate over the files inside because it would feel much more natural than for loop.

I’m banging my head over this for couple of evenings now, and I’m beginning to feel that it’s plain impossible.

I tried dozens of ways to structure my code but nothing seems to go my way.
Once I thought I had it, but then I realized I implemented an Iterator for a struct that can’t ever be instantiated :grin:.

I’m easily able to implement iterator returning an index into the ZipArchive, but there’s no point in doing it as you basically get the for loop.

My question is: is it possible? If so, please give me a hint. In case this can’t be done without unsafe I’d appreciate a code example as I didn’t yet grasp that part of language too much.


#3

Indeed, you can’t make an Iterator that takes a ZipArchive and yields ZipFile items. This is because a ZipFile mutably borrows the ZipArchive's reader, so a single archive can only have one ZipFile at a time. The Iterator trait can’t handle this restriction. You’d need a streaming iterator, which requires a slightly different trait that isn’t found in libstd.

You could implement an Iterator that reads the decompressed contents of each file and returns that:

pub struct ZipFiles<'a, R: Read + Seek + 'a> {
    i: usize,
    archive: &'a mut ZipArchive<R>,
}

impl<'a, R: Read + Seek + 'a> Iterator for ZipFiles<'a, R> {
    type Item = ZipResult<Vec<u8>>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i < self.archive.len() {
            self.i = i + 1;
            Some(self.archive.by_index(i).and_then(|mut file| {
                let mut content = vec![];
                try!(file.read_to_end(&mut content));
                Ok(content)
            }))
        } else {
            None
        }
    }
}

#4

Yeah, that’s what I thought, but didn’t yet have the knowledge to confirm.
Your answer helped me anyway:

  1. I’ll stop rewriting my 15 lines of code over and over :slight_smile:
  2. now I know I’m not that stupid :blush:

Thanks a lot!