1use std::{
2 fs::ReadDir,
3 sync::{Arc, Mutex},
4};
5
6use zip::ZipArchive;
7
8use crate::{VfsError, buffer::VfsBuffer};
9
10pub enum VfsListFiles {
11 Working(ReadDir),
12 ZipArchive {
13 index: usize,
14 prefix: Box<str>,
15 zip: Arc<Mutex<ZipArchive<VfsBuffer>>>,
16 },
17}
18
19impl VfsListFiles {
20 fn next_working(iter: &mut ReadDir) -> Option<<Self as Iterator>::Item> {
21 let mut name = None;
22 while name.is_none() {
23 match iter.next()?.map_err(Into::into) {
24 Ok(dir) => match dir.file_type().map_err(Into::into) {
25 Ok(it) => {
26 if it.is_file() {
27 name = dir.file_name().to_str().map(Into::into);
28 }
29 }
30 Err(err) => return Some(Err(err)),
31 },
32
33 Err(err) => {
34 return Some(Err(err));
35 }
36 }
37 }
38
39 return Some(Ok(name?));
40 }
41
42 fn next_zip(
43 index: &mut usize,
44 prefix: &Box<str>,
45 zip: &Arc<Mutex<ZipArchive<VfsBuffer>>>,
46 ) -> Option<<Self as Iterator>::Item> {
47 let Ok(mut zip) = zip.lock() else {
48 return Some(Err(VfsError::Other));
49 };
50
51 while *index < zip.len() {
52 let file = match zip.by_index(*index).map_err(Into::into) {
53 Ok(file) => file,
54 Err(err) => return Some(Err(err)),
55 };
56 *index += 1;
57
58 let name = file.name();
59 let prefix: &str = &prefix;
60 if name.starts_with(prefix) {
61 let remaining = &name[prefix.len()..];
62
63 if !remaining.contains('/') && file.is_file() {
64 return Some(Ok(remaining.to_string()));
65 }
66 }
67 }
68
69 return None;
70 }
71}
72
73impl Iterator for VfsListFiles {
74 type Item = Result<String, VfsError>;
75
76 fn next(&mut self) -> Option<Self::Item> {
77 match self {
78 Self::Working(iter) => Self::next_working(iter),
79
80 Self::ZipArchive { index, prefix, zip } => Self::next_zip(index, prefix, zip),
81 }
82 }
83}