This question could be asked in a few different ways but my end-goal is to encapsulate one file from a ZipArchive
(Rust zip crate) into a struct called ZipReader
that implements Read, like so:
struct ZipReader<R: Read + Seek> { ... }
impl<R: Read + Seek> ZipReader<R> {
fn from(src: R, filename: &str) -> ZipReader<R> { ... }
}
impl <R: Read + Seek> Read for ZipReader<R> { ... }
My effort to do so has involved constructing a new ZipArchive
from the src stream, then using ZipArchive.by_name(name)
to extract the ZipFile<'a>
from which bytes may be read.
The issue I run into is that the ZipFile<'a>
struct references the lifetime of the &'a mut ZipArchive
from which it was constructed -- meaning the ZipArchive
must remain in scope and remain mutably borrowed for the lifetime of the ZipFile
.
This combination of constraints seems to make it impossible to encapsulate the zip in a new struct:
pub struct ZipReader<R: Read + Seek> {
file: zip::read::ZipFile<'_>, // Have experimented with lifetimes here with no success
archive: ZipArchive<R>,
}
impl <R: Read + Seek> ZipReader<R> {
fn from(mut zip: R, name: &str) -> ZipReader<R> {
let archive = ZipArchive::new(zip);
let file = archive.by_name(name).unwrap();
ZipReader {
file: file,
archive: archive.unwrap(),
}
}
}
impl <R: Read + Seek> Read for ZipReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.file.read(buf)
}
}
I cannot move file
alone into the returned ZipReader
because archive
will go out of scope, but I cannot move archive
to ZipReader
because it is borrowed by file
.
It seems like modifying the zip crate and incorporating the ZipFile
state into ZipArchive
to eliminate the lifetime issue would be one way to solve the problem. How could this be solved without modifying anyone else's code?
As Coder-256 mentioned, owning_ref::OwningHandle
provides functionality to solve the borrowing problem, but not the lifetime problem. There is an open issue on the repo for owning_ref
that describes an equivalent situation and requests additional functionality to solve it, but it has been open since 2017 with no resolution.
I ended up modifying the zip crate to transfer ownership of the underlying stream instead of holding the reference to the ZipArchive. This is satisfactory enough for my purposes, but a solution like owning_ref
seems to be the correct approach for this type of problem.
Update: It seems the ouroboros
crate solves this problem in a more generic way, see: Open a single file from a ZIP archive and pass on as Read instance