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.rs113
1 files changed, 113 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..724606a3d
--- /dev/null
+++ b/crates/vfs/src/file_set.rs
@@ -0,0 +1,113 @@
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::{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 Default for FileSetConfig {
48 fn default() -> Self {
49 FileSetConfig::builder().build()
50 }
51}
52
53impl FileSetConfig {
54 pub fn builder() -> FileSetConfigBuilder {
55 FileSetConfigBuilder::default()
56 }
57 pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
58 let mut res = vec![FileSet::default(); self.len()];
59 for (file_id, path) in vfs.iter() {
60 let root = self.classify(&path);
61 res[root].insert(file_id, path)
62 }
63 res
64 }
65 fn len(&self) -> usize {
66 self.n_file_sets
67 }
68 fn classify(&self, path: &VfsPath) -> usize {
69 let path = match path.as_path() {
70 Some(it) => it,
71 None => return self.len() - 1,
72 };
73 let idx = match self.roots.binary_search_by(|(p, _)| p.as_path().cmp(path)) {
74 Ok(it) => it,
75 Err(it) => it.saturating_sub(1),
76 };
77 if path.starts_with(&self.roots[idx].0) {
78 self.roots[idx].1
79 } else {
80 self.len() - 1
81 }
82 }
83}
84
85pub struct FileSetConfigBuilder {
86 roots: Vec<Vec<AbsPathBuf>>,
87}
88
89impl Default for FileSetConfigBuilder {
90 fn default() -> Self {
91 FileSetConfigBuilder { roots: Vec::new() }
92 }
93}
94
95impl FileSetConfigBuilder {
96 pub fn len(&self) -> usize {
97 self.roots.len()
98 }
99 pub fn add_file_set(&mut self, roots: Vec<AbsPathBuf>) {
100 self.roots.push(roots)
101 }
102 pub fn build(self) -> FileSetConfig {
103 let n_file_sets = self.roots.len() + 1;
104 let mut roots: Vec<(AbsPathBuf, usize)> = self
105 .roots
106 .into_iter()
107 .enumerate()
108 .flat_map(|(i, paths)| paths.into_iter().zip(iter::repeat(i)))
109 .collect();
110 roots.sort();
111 FileSetConfig { n_file_sets, roots }
112 }
113}