1use std::{
2 borrow::Cow,
3 collections::BTreeMap,
4 path::{Path, PathBuf},
5};
6
7pub enum IncludeDir {
8 Fs(FsDirectory),
9 Included(IncludedDirectory),
10}
11
12pub enum FsOrIncludedFile {
13 Fs(FsFile),
14 Included(IncludedFile),
15}
16
17impl IncludeDir {
18 pub fn read(&self, path: &Path) -> Option<FsOrIncludedFile> {
19 match self {
20 IncludeDir::Fs(s) => s.read(path),
21 IncludeDir::Included(s) => s.read(path),
22 }
23 }
24}
25
26impl IntoIterator for IncludeDir {
27 type Item = (PathBuf, FsOrIncludedFile);
28 type IntoIter = FsOrIncludedIntoIter;
29 fn into_iter(self) -> Self::IntoIter {
30 match self {
31 IncludeDir::Fs(fs) => FsOrIncludedIntoIter::Fs(
32 walkdir::WalkDir::new(fs.0).sort_by_file_name().into_iter(),
33 ),
34 IncludeDir::Included(embedded) => {
35 FsOrIncludedIntoIter::Included(embedded.0.into_iter())
36 }
37 }
38 }
39}
40
41pub enum FsOrIncludedIntoIter {
42 Fs(walkdir::IntoIter),
43 Included(std::collections::btree_map::IntoIter<&'static Path, IncludedFile>),
44}
45
46impl Iterator for FsOrIncludedIntoIter {
47 type Item = (PathBuf, FsOrIncludedFile);
48 fn next(&mut self) -> Option<Self::Item> {
49 match self {
50 FsOrIncludedIntoIter::Fs(walkdir) => loop {
51 let entry = match walkdir.next() {
52 None => return None,
53 Some(Err(e)) => panic!("{}", e),
54 Some(Ok(entry)) => entry,
55 };
56 if entry.file_type().is_file() {
57 let path = entry.path().to_owned();
58 return Some((path.clone(), FsOrIncludedFile::Fs(FsFile(path))));
59 } else {
60 continue;
61 }
62 },
63 FsOrIncludedIntoIter::Included(map) => map
64 .next()
65 .map(|(path, file)| (path.to_owned(), FsOrIncludedFile::Included(file))),
66 }
67 }
68}
69
70impl FsOrIncludedFile {
71 pub fn data(&self) -> Cow<'static, [u8]> {
72 match self {
73 FsOrIncludedFile::Fs(s) => s.data(),
74 FsOrIncludedFile::Included(s) => s.data(),
75 }
76 }
77
78 pub fn hash(&self) -> Option<&'static str> {
79 match self {
80 FsOrIncludedFile::Fs(s) => s.hash(),
81 FsOrIncludedFile::Included(s) => s.hash(),
82 }
83 }
84}
85
86pub struct FsDirectory(pub PathBuf);
87
88impl FsDirectory {
89 pub fn read(&self, path: &Path) -> Option<FsOrIncludedFile> {
90 let path = self.0.join(path);
91 if path.exists() {
92 Some(FsOrIncludedFile::Fs(FsFile(path)))
93 } else {
94 None
95 }
96 }
97}
98
99pub struct FsFile(pub PathBuf);
100
101impl FsFile {
102 pub fn data(&self) -> Cow<'static, [u8]> {
103 Cow::Owned(std::fs::read(&self.0).unwrap())
104 }
105
106 pub fn hash(&self) -> Option<&'static str> {
107 None
108 }
109}
110
111#[derive(Debug)]
112pub struct IncludedDirectory(pub BTreeMap<&'static Path, IncludedFile>);
113
114#[derive(Clone, Debug)]
115pub struct IncludedFile {
116 pub data: &'static [u8],
117 pub hash: &'static str,
118}
119
120impl IncludedDirectory {
121 pub fn read(&self, path: &Path) -> Option<FsOrIncludedFile> {
122 self.0
123 .get(path)
124 .map(|file| FsOrIncludedFile::Included(file.clone()))
125 }
126}
127
128impl IncludedFile {
129 pub fn data(&self) -> Cow<'static, [u8]> {
130 Cow::Borrowed(self.data)
131 }
132
133 pub fn hash(&self) -> Option<&'static str> {
134 Some(self.hash)
135 }
136}