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>> {
62 let file = crate::base::read::file(&mut reader).await?;
63 Ok(ZipFileReader::from_raw_parts(reader, file))
64 }
65
66 pub fn from_raw_parts(reader: R, file: ZipFile) -> ZipFileReader<R> {
70 ZipFileReader { reader, file: Arc::new(file) }
71 }
72
73 pub fn file(&self) -> &ZipFile {
75 &self.file
76 }
77
78 pub fn inner_mut(&mut self) -> &mut R {
82 &mut self.reader
83 }
84
85 pub fn into_inner(self) -> R {
87 self.reader
88 }
89
90 pub async fn reader_without_entry(&mut self, index: usize) -> Result<ZipEntryReader<'_, R, WithoutEntry>> {
92 let stored_entry = self.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
93 stored_entry.seek_to_data_offset(&mut self.reader).await?;
94
95 ZipEntryReader::new_with_borrow(
96 &mut self.reader,
97 stored_entry.entry.compression(),
98 stored_entry.entry.compressed_size(),
99 )
100 }
101
102 pub async fn reader_with_entry(&mut self, index: usize) -> Result<ZipEntryReader<'_, R, WithEntry<'_>>> {
104 let stored_entry = self.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
105
106 stored_entry.seek_to_data_offset(&mut self.reader).await?;
107
108 let reader = ZipEntryReader::new_with_borrow(
109 &mut self.reader,
110 stored_entry.entry.compression(),
111 stored_entry.entry.compressed_size(),
112 )?;
113
114 Ok(reader.into_with_entry(stored_entry))
115 }
116
117 pub async fn into_entry<'a>(mut self, index: usize) -> Result<ZipEntryReader<'a, R, WithoutEntry>>
120 where
121 R: 'a,
122 {
123 let stored_entry = self.file.entries.get(index).ok_or(ZipError::EntryIndexOutOfBounds)?;
124
125 stored_entry.seek_to_data_offset(&mut self.reader).await?;
126
127 ZipEntryReader::new_with_owned(
128 self.reader,
129 stored_entry.entry.compression(),
130 stored_entry.entry.compressed_size(),
131 )
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use std::sync::Arc;
138
139 use futures_lite::io::Cursor;
140
141 use super::ZipFileReader;
142 use crate::ZipFileBuilder;
143
144 #[test]
145 fn clone_shares_file_metadata() {
146 let reader = ZipFileReader::from_raw_parts(Cursor::new(Vec::new()), ZipFileBuilder::new().build());
147 let cloned_reader = reader.clone();
148
149 assert!(Arc::ptr_eq(&reader.file, &cloned_reader.file));
150 }
151}
152
153#[cfg(feature = "tokio")]
154impl<R> ZipFileReader<Compat<R>>
155where
156 R: tokio::io::AsyncBufRead + tokio::io::AsyncSeek + Unpin,
157{
158 pub async fn with_tokio(reader: R) -> Result<TokioZipFileReader<R>> {
160 let mut reader = reader.compat();
161 let file = crate::base::read::file(&mut reader).await?;
162 Ok(ZipFileReader::from_raw_parts(reader, file))
163 }
164}