async_zip/base/read/
seek.rs1use crate::base::read::io::entry::ZipEntryReader;
30use crate::error::{Result, ZipError};
31use crate::file::ZipFile;
32use std::sync::Arc;
33
34#[cfg(feature = "tokio")]
35use crate::tokio::read::seek::ZipFileReader as TokioZipFileReader;
36
37use futures_lite::io::{AsyncBufRead, AsyncSeek};
38
39#[cfg(feature = "tokio")]
40use tokio_util::compat::{Compat, TokioAsyncReadCompatExt};
41
42use super::io::entry::{WithEntry, WithoutEntry};
43
44#[derive(Clone)]
46pub struct ZipFileReader<R> {
47 reader: R,
48 file: Arc<ZipFile>,
49}
50
51impl<R> ZipFileReader<R>
52where
53 R: AsyncBufRead + AsyncSeek + Unpin,
54{
55 pub async fn new(mut reader: R) -> Result<ZipFileReader<R>> {
57 let file = crate::base::read::file(&mut reader).await?;
58 Ok(ZipFileReader::from_raw_parts(reader, file))
59 }
60
61 pub fn from_raw_parts(reader: R, file: ZipFile) -> ZipFileReader<R> {
65 ZipFileReader { reader, file: Arc::new(file) }
66 }
67
68 pub fn file(&self) -> &ZipFile {
70 &self.file
71 }
72
73 pub fn inner_mut(&mut self) -> &mut R {
77 &mut self.reader
78 }
79
80 pub fn into_inner(self) -> R {
82 self.reader
83 }
84
85 pub async fn reader_without_entry(&mut self, index: usize) -> Result<ZipEntryReader<'_, R, WithoutEntry>> {
87 let stored_entry = self.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
88 stored_entry.seek_to_data_offset(&mut self.reader).await?;
89
90 Ok(ZipEntryReader::new_with_borrow(
91 &mut self.reader,
92 stored_entry.entry.compression(),
93 stored_entry.entry.compressed_size(),
94 ))
95 }
96
97 pub async fn reader_with_entry(&mut self, index: usize) -> Result<ZipEntryReader<'_, R, WithEntry<'_>>> {
99 let stored_entry = self.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
100
101 stored_entry.seek_to_data_offset(&mut self.reader).await?;
102
103 let reader = ZipEntryReader::new_with_borrow(
104 &mut self.reader,
105 stored_entry.entry.compression(),
106 stored_entry.entry.compressed_size(),
107 );
108
109 Ok(reader.into_with_entry(stored_entry))
110 }
111
112 pub async fn into_entry<'a>(mut self, index: usize) -> Result<ZipEntryReader<'a, R, WithoutEntry>>
115 where
116 R: 'a,
117 {
118 let stored_entry = self.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
119
120 stored_entry.seek_to_data_offset(&mut self.reader).await?;
121
122 Ok(ZipEntryReader::new_with_owned(
123 self.reader,
124 stored_entry.entry.compression(),
125 stored_entry.entry.compressed_size(),
126 ))
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use std::sync::Arc;
133
134 use futures_lite::io::Cursor;
135
136 use super::ZipFileReader;
137 use crate::ZipFileBuilder;
138
139 #[test]
140 fn clone_shares_file_metadata() {
141 let reader = ZipFileReader::from_raw_parts(Cursor::new(Vec::new()), ZipFileBuilder::new().build());
142 let cloned_reader = reader.clone();
143
144 assert!(Arc::ptr_eq(&reader.file, &cloned_reader.file));
145 }
146}
147
148#[cfg(feature = "tokio")]
149impl<R> ZipFileReader<Compat<R>>
150where
151 R: tokio::io::AsyncBufRead + tokio::io::AsyncSeek + Unpin,
152{
153 pub async fn with_tokio(reader: R) -> Result<TokioZipFileReader<R>> {
155 let mut reader = reader.compat();
156 let file = crate::base::read::file(&mut reader).await?;
157 Ok(ZipFileReader::from_raw_parts(reader, file))
158 }
159}