1use std::fmt;
6
7use fst::{IntoStreamer, Streamer};
8use indexmap::IndexMap;
9use rustc_hash::{FxBuildHasher, FxHashMap};
10
11use crate::{AnchoredPath, FileId, Vfs, VfsPath};
12
13#[derive(Default, Clone, Eq, PartialEq)]
15pub struct FileSet {
16 files: FxHashMap<VfsPath, FileId>,
17 paths: IndexMap<FileId, VfsPath, FxBuildHasher>,
18}
19
20impl FileSet {
21 pub fn len(&self) -> usize {
23 self.files.len()
24 }
25
26 pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
31 let mut base = self.paths[&path.anchor].clone();
32 base.pop();
33 let path = base.join(path.path)?;
34 self.files.get(&path).copied()
35 }
36
37 pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> {
39 self.files.get(path)
40 }
41
42 pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> {
44 self.paths.get(file)
45 }
46
47 pub fn insert(&mut self, file_id: FileId, path: VfsPath) {
52 self.files.insert(path.clone(), file_id);
53 self.paths.insert(file_id, path);
54 }
55
56 pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
58 self.paths.keys().copied()
59 }
60}
61
62impl fmt::Debug for FileSet {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.debug_struct("FileSet").field("n_files", &self.files.len()).finish()
65 }
66}
67
68#[derive(Debug)]
86pub struct FileSetConfig {
87 n_file_sets: usize,
92 map: fst::Map<Vec<u8>>,
94}
95
96impl Default for FileSetConfig {
97 fn default() -> Self {
98 FileSetConfig::builder().build()
99 }
100}
101
102impl FileSetConfig {
103 pub fn builder() -> FileSetConfigBuilder {
105 FileSetConfigBuilder::default()
106 }
107
108 pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
112 let mut scratch_space = Vec::new();
113 let mut res = vec![FileSet::default(); self.len()];
114 for (file_id, path) in vfs.iter() {
115 let root = self.classify(path, &mut scratch_space);
116 res[root].insert(file_id, path.clone());
117 }
118 res
119 }
120
121 fn len(&self) -> usize {
123 self.n_file_sets
124 }
125
126 pub fn roots(&self) -> Vec<(Vec<u8>, u64)> {
128 self.map.stream().into_byte_vec()
129 }
130
131 fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize {
135 let path = path.parent().unwrap_or_else(|| path.clone());
138
139 scratch_space.clear();
140 path.encode(scratch_space);
141 let automaton = PrefixOf::new(scratch_space.as_slice());
142 let mut longest_prefix = self.len() - 1;
143 let mut stream = self.map.search(automaton).into_stream();
144 while let Some((_, v)) = stream.next() {
145 longest_prefix = v as usize;
146 }
147 longest_prefix
148 }
149}
150
151#[derive(Default)]
153pub struct FileSetConfigBuilder {
154 roots: Vec<Vec<VfsPath>>,
155}
156
157impl FileSetConfigBuilder {
158 pub fn len(&self) -> usize {
160 self.roots.len()
161 }
162
163 pub fn add_file_set(&mut self, roots: Vec<VfsPath>) {
165 self.roots.push(roots);
166 }
167
168 pub fn build(self) -> FileSetConfig {
170 let n_file_sets = self.roots.len() + 1;
171 let map = {
172 let mut entries = Vec::new();
173 for (i, paths) in self.roots.into_iter().enumerate() {
174 for p in paths {
175 let mut buf = Vec::new();
176 p.encode(&mut buf);
177 entries.push((buf, i as u64));
178 }
179 }
180 entries.sort();
181 entries.dedup_by(|(a, _), (b, _)| a == b);
182 fst::Map::from_iter(entries).unwrap()
183 };
184 FileSetConfig { n_file_sets, map }
185 }
186}
187
188struct PrefixOf<'a> {
192 prefix_of: &'a [u8],
193}
194
195impl<'a> PrefixOf<'a> {
196 fn new(prefix_of: &'a [u8]) -> Self {
198 Self { prefix_of }
199 }
200}
201
202impl fst::Automaton for PrefixOf<'_> {
203 type State = usize;
204 fn start(&self) -> usize {
205 0
206 }
207 fn is_match(&self, &state: &usize) -> bool {
208 state != !0
209 }
210 fn can_match(&self, &state: &usize) -> bool {
211 state != !0
212 }
213 fn accept(&self, &state: &usize, byte: u8) -> usize {
214 if self.prefix_of.get(state) == Some(&byte) { state + 1 } else { !0 }
215 }
216}
217
218#[cfg(test)]
219mod tests;