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 .
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.
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
}
}
}