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.rs135
1 files changed, 114 insertions, 21 deletions
diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs
index d0ddeafe7..e9196fcd2 100644
--- a/crates/vfs/src/file_set.rs
+++ b/crates/vfs/src/file_set.rs
@@ -2,8 +2,9 @@
2//! 2//!
3//! Files which do not belong to any explicitly configured `FileSet` belong to 3//! Files which do not belong to any explicitly configured `FileSet` belong to
4//! the default `FileSet`. 4//! the default `FileSet`.
5use std::{fmt, iter}; 5use std::fmt;
6 6
7use fst::{IntoStreamer, Streamer};
7use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
8 9
9use crate::{FileId, Vfs, VfsPath}; 10use crate::{FileId, Vfs, VfsPath};
@@ -15,6 +16,9 @@ pub struct FileSet {
15} 16}
16 17
17impl FileSet { 18impl FileSet {
19 pub fn len(&self) -> usize {
20 self.files.len()
21 }
18 pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 22 pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
19 let mut base = self.paths[&anchor].clone(); 23 let mut base = self.paths[&anchor].clone();
20 base.pop(); 24 base.pop();
@@ -40,7 +44,7 @@ impl fmt::Debug for FileSet {
40#[derive(Debug)] 44#[derive(Debug)]
41pub struct FileSetConfig { 45pub struct FileSetConfig {
42 n_file_sets: usize, 46 n_file_sets: usize,
43 roots: Vec<(VfsPath, usize)>, 47 map: fst::Map<Vec<u8>>,
44} 48}
45 49
46impl Default for FileSetConfig { 50impl Default for FileSetConfig {
@@ -54,26 +58,27 @@ impl FileSetConfig {
54 FileSetConfigBuilder::default() 58 FileSetConfigBuilder::default()
55 } 59 }
56 pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> { 60 pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
61 let mut scratch_space = Vec::new();
57 let mut res = vec![FileSet::default(); self.len()]; 62 let mut res = vec![FileSet::default(); self.len()];
58 for (file_id, path) in vfs.iter() { 63 for (file_id, path) in vfs.iter() {
59 let root = self.classify(&path); 64 let root = self.classify(&path, &mut scratch_space);
60 res[root].insert(file_id, path) 65 res[root].insert(file_id, path.clone())
61 } 66 }
62 res 67 res
63 } 68 }
64 fn len(&self) -> usize { 69 fn len(&self) -> usize {
65 self.n_file_sets 70 self.n_file_sets
66 } 71 }
67 fn classify(&self, path: &VfsPath) -> usize { 72 fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize {
68 let idx = match self.roots.binary_search_by(|(p, _)| p.cmp(path)) { 73 scratch_space.clear();
69 Ok(it) => it, 74 path.encode(scratch_space);
70 Err(it) => it.saturating_sub(1), 75 let automaton = PrefixOf::new(scratch_space.as_slice());
71 }; 76 let mut longest_prefix = self.len() - 1;
72 if path.starts_with(&self.roots[idx].0) { 77 let mut stream = self.map.search(automaton).into_stream();
73 self.roots[idx].1 78 while let Some((_, v)) = stream.next() {
74 } else { 79 longest_prefix = v as usize;
75 self.len() - 1
76 } 80 }
81 longest_prefix
77 } 82 }
78} 83}
79 84
@@ -96,13 +101,101 @@ impl FileSetConfigBuilder {
96 } 101 }
97 pub fn build(self) -> FileSetConfig { 102 pub fn build(self) -> FileSetConfig {
98 let n_file_sets = self.roots.len() + 1; 103 let n_file_sets = self.roots.len() + 1;
99 let mut roots: Vec<(VfsPath, usize)> = self 104 let map = {
100 .roots 105 let mut entries = Vec::new();
101 .into_iter() 106 for (i, paths) in self.roots.into_iter().enumerate() {
102 .enumerate() 107 for p in paths {
103 .flat_map(|(i, paths)| paths.into_iter().zip(iter::repeat(i))) 108 let mut buf = Vec::new();
104 .collect(); 109 p.encode(&mut buf);
105 roots.sort(); 110 entries.push((buf, i as u64));
106 FileSetConfig { n_file_sets, roots } 111 }
112 }
113 entries.sort();
114 entries.dedup_by(|(a, _), (b, _)| a == b);
115 fst::Map::from_iter(entries).unwrap()
116 };
117 FileSetConfig { n_file_sets, map }
118 }
119}
120
121struct PrefixOf<'a> {
122 prefix_of: &'a [u8],
123}
124
125impl<'a> PrefixOf<'a> {
126 fn new(prefix_of: &'a [u8]) -> Self {
127 Self { prefix_of }
128 }
129}
130
131impl fst::Automaton for PrefixOf<'_> {
132 type State = usize;
133 fn start(&self) -> usize {
134 0
135 }
136 fn is_match(&self, &state: &usize) -> bool {
137 state != !0
138 }
139 fn can_match(&self, &state: &usize) -> bool {
140 state != !0
141 }
142 fn accept(&self, &state: &usize, byte: u8) -> usize {
143 if self.prefix_of.get(state) == Some(&byte) {
144 state + 1
145 } else {
146 !0
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn path_prefix() {
157 let mut file_set = FileSetConfig::builder();
158 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
159 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]);
160 let file_set = file_set.build();
161
162 let mut vfs = Vfs::default();
163 vfs.set_file_contents(
164 VfsPath::new_virtual_path("/foo/src/lib.rs".into()),
165 Some(Vec::new()),
166 );
167 vfs.set_file_contents(
168 VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()),
169 Some(Vec::new()),
170 );
171 vfs.set_file_contents(
172 VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()),
173 Some(Vec::new()),
174 );
175 vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new()));
176
177 let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
178 assert_eq!(partition, vec![2, 1, 1]);
179 }
180
181 #[test]
182 fn name_prefix() {
183 let mut file_set = FileSetConfig::builder();
184 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
185 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo-things".into())]);
186 let file_set = file_set.build();
187
188 let mut vfs = Vfs::default();
189 vfs.set_file_contents(
190 VfsPath::new_virtual_path("/foo/src/lib.rs".into()),
191 Some(Vec::new()),
192 );
193 vfs.set_file_contents(
194 VfsPath::new_virtual_path("/foo-things/src/lib.rs".into()),
195 Some(Vec::new()),
196 );
197
198 let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
199 assert_eq!(partition, vec![1, 1, 0]);
107 } 200 }
108} 201}