aboutsummaryrefslogtreecommitdiff
path: root/crates/vfs/src/file_set.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/vfs/src/file_set.rs')
-rw-r--r--crates/vfs/src/file_set.rs99
1 files changed, 99 insertions, 0 deletions
diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs
new file mode 100644
index 000000000..7dc721f7e
--- /dev/null
+++ b/crates/vfs/src/file_set.rs
@@ -0,0 +1,99 @@
1//! Partitions a list of files into disjoint subsets.
2//!
3//! Files which do not belong to any explicitly configured `FileSet` belong to
4//! the default `FileSet`.
5use std::{cmp, fmt, iter};
6
7use paths::AbsPathBuf;
8use rustc_hash::FxHashMap;
9
10use crate::{FileId, Vfs, VfsPath};
11
12#[derive(Default, Clone, Eq, PartialEq)]
13pub struct FileSet {
14 files: FxHashMap<VfsPath, FileId>,
15 paths: FxHashMap<FileId, VfsPath>,
16}
17
18impl FileSet {
19 pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
20 let mut base = self.paths[&anchor].clone();
21 base.pop();
22 let path = base.join(path);
23 let res = self.files.get(&path).copied();
24 res
25 }
26 pub fn insert(&mut self, file_id: FileId, path: VfsPath) {
27 self.files.insert(path.clone(), file_id);
28 self.paths.insert(file_id, path);
29 }
30 pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
31 self.paths.keys().copied()
32 }
33}
34
35impl fmt::Debug for FileSet {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.debug_struct("FileSet").field("n_files", &self.files.len()).finish()
38 }
39}
40
41#[derive(Debug)]
42pub struct FileSetConfig {
43 n_file_sets: usize,
44 roots: Vec<(AbsPathBuf, usize)>,
45}
46
47impl FileSetConfig {
48 pub fn builder() -> FileSetConfigBuilder {
49 FileSetConfigBuilder::default()
50 }
51 pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
52 let mut res = vec![FileSet::default(); self.len()];
53 for (file_id, path) in vfs.iter() {
54 let root = self.classify(&path);
55 res[root].insert(file_id, path)
56 }
57 res
58 }
59 fn len(&self) -> usize {
60 self.n_file_sets
61 }
62 fn classify(&self, path: &VfsPath) -> usize {
63 for (root, idx) in self.roots.iter() {
64 if let Some(path) = path.as_path() {
65 if path.starts_with(root) {
66 return *idx;
67 }
68 }
69 }
70 self.len() - 1
71 }
72}
73
74pub struct FileSetConfigBuilder {
75 roots: Vec<Vec<AbsPathBuf>>,
76}
77
78impl Default for FileSetConfigBuilder {
79 fn default() -> Self {
80 FileSetConfigBuilder { roots: Vec::new() }
81 }
82}
83
84impl FileSetConfigBuilder {
85 pub fn add_file_set(&mut self, roots: Vec<AbsPathBuf>) {
86 self.roots.push(roots)
87 }
88 pub fn build(self) -> FileSetConfig {
89 let n_file_sets = self.roots.len() + 1;
90 let mut roots: Vec<(AbsPathBuf, usize)> = self
91 .roots
92 .into_iter()
93 .enumerate()
94 .flat_map(|(i, paths)| paths.into_iter().zip(iter::repeat(i)))
95 .collect();
96 roots.sort_by_key(|(path, _)| cmp::Reverse(path.to_string_lossy().len()));
97 FileSetConfig { n_file_sets, roots }
98 }
99}