aboutsummaryrefslogtreecommitdiff
path: root/vfs/src
diff options
context:
space:
mode:
Diffstat (limited to 'vfs/src')
-rw-r--r--vfs/src/lib.rs89
1 files changed, 89 insertions, 0 deletions
diff --git a/vfs/src/lib.rs b/vfs/src/lib.rs
new file mode 100644
index 0000000..f620ab9
--- /dev/null
+++ b/vfs/src/lib.rs
@@ -0,0 +1,89 @@
1use std::{
2 collections::HashMap,
3 default::Default,
4 path::{Path, PathBuf},
5};
6
7use indexmap::IndexSet;
8
9#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
10pub struct FileId(u32);
11
12#[derive(Debug, Default)]
13pub struct Interner {
14 map: IndexSet<PathBuf>,
15}
16
17impl Interner {
18 pub fn get<P: AsRef<Path>>(&self, path: P) -> Option<FileId> {
19 self.map
20 .get_index_of(path.as_ref())
21 .map(|i| FileId(i as u32))
22 }
23 pub fn intern(&mut self, path: PathBuf) -> FileId {
24 let (id, _) = self.map.insert_full(path);
25 FileId(id as u32)
26 }
27 pub fn lookup(&self, file: FileId) -> Option<&Path> {
28 self.map.get_index(file.0 as usize).map(|p| p.as_path())
29 }
30}
31
32#[derive(Default)]
33pub struct ReadOnlyVfs {
34 interner: Interner,
35 data: HashMap<FileId, Vec<u8>>,
36}
37
38impl ReadOnlyVfs {
39 pub fn alloc_file_id<P: AsRef<Path>>(&mut self, path: P) -> FileId {
40 self.interner.intern(path.as_ref().to_owned())
41 }
42 pub fn len(&self) -> usize {
43 self.data.len()
44 }
45 pub fn file_path(&self, file_id: FileId) -> &Path {
46 self.interner.lookup(file_id).unwrap()
47 }
48 pub fn get(&self, file_id: FileId) -> &Vec<u8> {
49 self.data.get(&file_id).unwrap()
50 }
51 pub fn get_str(&self, file_id: FileId) -> &str {
52 std::str::from_utf8(self.get(file_id)).unwrap()
53 }
54 pub fn get_mut(&mut self, file_id: FileId) -> &mut Vec<u8> {
55 self.data.get_mut(&file_id).unwrap()
56 }
57 pub fn set_file_contents<P: AsRef<Path>>(&mut self, path: P, contents: &[u8]) {
58 let file_id = self.alloc_file_id(path);
59 self.data.insert(file_id, contents.to_owned());
60 }
61 pub fn iter<'ρ>(&'ρ self) -> impl Iterator<Item = VfsEntry<'ρ>> {
62 self.data.iter().map(move |(file_id, _)| VfsEntry {
63 file_id: *file_id,
64 file_path: self.file_path(*file_id),
65 contents: self.get_str(*file_id),
66 })
67 }
68}
69
70pub struct VfsEntry<'ρ> {
71 pub file_id: FileId,
72 pub file_path: &'ρ Path,
73 pub contents: &'ρ str,
74}
75
76#[cfg(test)]
77mod test {
78 use super::*;
79
80 #[test]
81 fn trivial() {
82 let mut vfs = ReadOnlyVfs::default();
83 let f1 = "a/b/c";
84 let id1 = vfs.alloc_file_id(f1);
85 let data = "hello".as_bytes().to_vec();
86 vfs.set_file_contents(f1, &data);
87 assert_eq!(vfs.get(id1), &data);
88 }
89}