sunfish/
include_dir.rs

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}