1use crate::format::{FileInfo, Format, FormatStep};
2
3use futures_lite::io::{
4 AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, Error, ErrorKind,
5 Result, SeekFrom,
6};
7use std::collections::HashMap;
8
9#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
17#[derive(Debug)]
18pub struct AsyncArchive<R> {
19 inner: R,
20 files: HashMap<String, FileInfo>,
21}
22
23impl<R> AsyncArchive<R>
24where
25 R: AsyncRead + AsyncSeek + Unpin,
26{
27 pub async fn new(mut inner: R) -> Result<Self> {
32 let mut fmt = Format::new();
33 loop {
34 match fmt.next()? {
35 FormatStep::Read(s, ref mut buf) => {
36 inner.seek(s).await?;
37 inner.read_exact(buf).await?;
38 }
39
40 FormatStep::Done(filesvec) => {
41 let mut files = HashMap::with_capacity(filesvec.len());
42 for f in filesvec.into_iter() {
43 files.insert(f.path.clone(), f);
44 }
45 return Ok(AsyncArchive { inner, files });
46 }
47 }
48 }
49 }
50
51 pub fn list(&self) -> impl Iterator<Item = &FileInfo> {
53 self.files.values()
54 }
55
56 fn find(&self, path: &str) -> Result<&FileInfo> {
57 self.files
58 .get(path)
59 .ok_or_else(|| Error::new(ErrorKind::NotFound, "file not found"))
60 }
61
62 pub async fn load(&mut self, path: &str) -> Result<Vec<u8>> {
64 explode::explode(&self.load_compressed(path).await?)
65 .map_err(|e| Error::new(ErrorKind::InvalidData, e))
66 }
67
68 pub async fn load_compressed(&mut self, path: &str) -> Result<Vec<u8>> {
70 let info = self.find(path)?;
71 let size = info.size;
72 let offset = info.offset;
73 let mut ret = vec![0; size];
74 self.inner.seek(SeekFrom::Start(offset)).await?;
75 self.inner.read_exact(&mut ret).await?;
76 Ok(ret)
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::AsyncArchive;
83 use crate::examples::EXAMPLES;
84 use futures_lite::io::Cursor;
85
86 #[test]
87 fn archive_new() {
88 let ex = async_executor::LocalExecutor::new();
89 for (arcdata, _files) in EXAMPLES {
90 ex.run(async {
91 let c = Cursor::new(arcdata);
92 let _ar = AsyncArchive::new(c).await.unwrap();
93 });
94 }
95 }
96
97 #[test]
98 fn archive_list() {
99 let ex = async_executor::LocalExecutor::new();
100 for (arcdata, files) in EXAMPLES {
101 ex.run(async {
102 let c = Cursor::new(arcdata);
103 let ar = AsyncArchive::new(c).await.unwrap();
104 for file in ar.list() {
106 let i = files.iter().find(|(name, _)| *name == file.path);
107 if i.is_none() {
108 panic!("unexpected file {:?}", file.path);
109 }
110 }
111 });
112 }
113 }
114
115 #[test]
116 fn archive_load() {
117 let ex = async_executor::LocalExecutor::new();
118 for (arcdata, files) in EXAMPLES {
119 let c = Cursor::new(arcdata);
120 ex.run(async {
121 let mut ar = AsyncArchive::new(c).await.unwrap();
122 for (fname, contents) in files.iter() {
124 let ours = ar.load(fname).await.unwrap();
125 assert_eq!(ours, *contents);
126 }
127 });
128 }
129 }
130}