diff options
Diffstat (limited to 'crates/vfs/src/file_set.rs')
-rw-r--r-- | crates/vfs/src/file_set.rs | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index 49ca593ac..0a4590c8d 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs | |||
@@ -9,6 +9,7 @@ use rustc_hash::FxHashMap; | |||
9 | 9 | ||
10 | use crate::{AnchoredPath, FileId, Vfs, VfsPath}; | 10 | use crate::{AnchoredPath, FileId, Vfs, VfsPath}; |
11 | 11 | ||
12 | /// A set of [`VfsPath`]s identified by [`FileId`]s. | ||
12 | #[derive(Default, Clone, Eq, PartialEq)] | 13 | #[derive(Default, Clone, Eq, PartialEq)] |
13 | pub struct FileSet { | 14 | pub struct FileSet { |
14 | files: FxHashMap<VfsPath, FileId>, | 15 | files: FxHashMap<VfsPath, FileId>, |
@@ -16,9 +17,15 @@ pub struct FileSet { | |||
16 | } | 17 | } |
17 | 18 | ||
18 | impl FileSet { | 19 | impl FileSet { |
20 | /// Returns the number of stored paths. | ||
19 | pub fn len(&self) -> usize { | 21 | pub fn len(&self) -> usize { |
20 | self.files.len() | 22 | self.files.len() |
21 | } | 23 | } |
24 | |||
25 | /// Get the id of the file corresponding to `path`. | ||
26 | /// | ||
27 | /// If either `path`'s [`anchor`](AnchoredPath::anchor) or the resolved path is not in | ||
28 | /// the set, returns [`None`]. | ||
22 | pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> { | 29 | pub fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> { |
23 | let mut base = self.paths[&path.anchor].clone(); | 30 | let mut base = self.paths[&path.anchor].clone(); |
24 | base.pop(); | 31 | base.pop(); |
@@ -26,19 +33,26 @@ impl FileSet { | |||
26 | self.files.get(&path).copied() | 33 | self.files.get(&path).copied() |
27 | } | 34 | } |
28 | 35 | ||
36 | /// Get the id corresponding to `path` if it exists in the set. | ||
29 | pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { | 37 | pub fn file_for_path(&self, path: &VfsPath) -> Option<&FileId> { |
30 | self.files.get(path) | 38 | self.files.get(path) |
31 | } | 39 | } |
32 | 40 | ||
41 | /// Get the path corresponding to `file` if it exists in the set. | ||
33 | pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { | 42 | pub fn path_for_file(&self, file: &FileId) -> Option<&VfsPath> { |
34 | self.paths.get(file) | 43 | self.paths.get(file) |
35 | } | 44 | } |
36 | 45 | ||
46 | /// Insert the `file_id, path` pair into the set. | ||
47 | /// | ||
48 | /// # Note | ||
49 | /// Multiple [`FileId`] can be mapped to the same [`VfsPath`], and vice-versa. | ||
37 | pub fn insert(&mut self, file_id: FileId, path: VfsPath) { | 50 | pub fn insert(&mut self, file_id: FileId, path: VfsPath) { |
38 | self.files.insert(path.clone(), file_id); | 51 | self.files.insert(path.clone(), file_id); |
39 | self.paths.insert(file_id, path); | 52 | self.paths.insert(file_id, path); |
40 | } | 53 | } |
41 | 54 | ||
55 | /// Iterate over this set's ids. | ||
42 | pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ { | 56 | pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ { |
43 | self.paths.keys().copied() | 57 | self.paths.keys().copied() |
44 | } | 58 | } |
@@ -50,9 +64,31 @@ impl fmt::Debug for FileSet { | |||
50 | } | 64 | } |
51 | } | 65 | } |
52 | 66 | ||
67 | /// This contains path prefixes to partition a [`Vfs`] into [`FileSet`]s. | ||
68 | /// | ||
69 | /// # Example | ||
70 | /// ```rust | ||
71 | /// # use vfs::{file_set::FileSetConfigBuilder, VfsPath, Vfs}; | ||
72 | /// let mut builder = FileSetConfigBuilder::default(); | ||
73 | /// builder.add_file_set(vec![VfsPath::new_virtual_path("/src".to_string())]); | ||
74 | /// let config = builder.build(); | ||
75 | /// let mut file_system = Vfs::default(); | ||
76 | /// file_system.set_file_contents(VfsPath::new_virtual_path("/src/main.rs".to_string()), Some(vec![])); | ||
77 | /// file_system.set_file_contents(VfsPath::new_virtual_path("/src/lib.rs".to_string()), Some(vec![])); | ||
78 | /// file_system.set_file_contents(VfsPath::new_virtual_path("/build.rs".to_string()), Some(vec![])); | ||
79 | /// // contains the sets : | ||
80 | /// // { "/src/main.rs", "/src/lib.rs" } | ||
81 | /// // { "build.rs" } | ||
82 | /// let sets = config.partition(&file_system); | ||
83 | /// ``` | ||
53 | #[derive(Debug)] | 84 | #[derive(Debug)] |
54 | pub struct FileSetConfig { | 85 | pub struct FileSetConfig { |
86 | /// Number of sets that `self` can partition a [`Vfs`] into. | ||
87 | /// | ||
88 | /// This should be the number of sets in `self.map` + 1 for files that don't fit in any | ||
89 | /// defined set. | ||
55 | n_file_sets: usize, | 90 | n_file_sets: usize, |
91 | /// Map from encoded paths to the set they belong to. | ||
56 | map: fst::Map<Vec<u8>>, | 92 | map: fst::Map<Vec<u8>>, |
57 | } | 93 | } |
58 | 94 | ||
@@ -63,9 +99,14 @@ impl Default for FileSetConfig { | |||
63 | } | 99 | } |
64 | 100 | ||
65 | impl FileSetConfig { | 101 | impl FileSetConfig { |
102 | /// Returns a builder for `FileSetConfig`. | ||
66 | pub fn builder() -> FileSetConfigBuilder { | 103 | pub fn builder() -> FileSetConfigBuilder { |
67 | FileSetConfigBuilder::default() | 104 | FileSetConfigBuilder::default() |
68 | } | 105 | } |
106 | |||
107 | /// Partition `vfs` into `FileSet`s. | ||
108 | /// | ||
109 | /// Creates a new [`FileSet`] for every set of prefixes in `self`. | ||
69 | pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> { | 110 | pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> { |
70 | let mut scratch_space = Vec::new(); | 111 | let mut scratch_space = Vec::new(); |
71 | let mut res = vec![FileSet::default(); self.len()]; | 112 | let mut res = vec![FileSet::default(); self.len()]; |
@@ -75,9 +116,15 @@ impl FileSetConfig { | |||
75 | } | 116 | } |
76 | res | 117 | res |
77 | } | 118 | } |
119 | |||
120 | /// Number of sets that `self` can partition a [`Vfs`] into. | ||
78 | fn len(&self) -> usize { | 121 | fn len(&self) -> usize { |
79 | self.n_file_sets | 122 | self.n_file_sets |
80 | } | 123 | } |
124 | |||
125 | /// Returns the set index for the given `path`. | ||
126 | /// | ||
127 | /// `scratch_space` is used as a buffer and will be entirely replaced. | ||
81 | fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize { | 128 | fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize { |
82 | scratch_space.clear(); | 129 | scratch_space.clear(); |
83 | path.encode(scratch_space); | 130 | path.encode(scratch_space); |
@@ -91,6 +138,7 @@ impl FileSetConfig { | |||
91 | } | 138 | } |
92 | } | 139 | } |
93 | 140 | ||
141 | /// Builder for [`FileSetConfig`]. | ||
94 | pub struct FileSetConfigBuilder { | 142 | pub struct FileSetConfigBuilder { |
95 | roots: Vec<Vec<VfsPath>>, | 143 | roots: Vec<Vec<VfsPath>>, |
96 | } | 144 | } |
@@ -102,12 +150,17 @@ impl Default for FileSetConfigBuilder { | |||
102 | } | 150 | } |
103 | 151 | ||
104 | impl FileSetConfigBuilder { | 152 | impl FileSetConfigBuilder { |
153 | /// Returns the number of sets currently held. | ||
105 | pub fn len(&self) -> usize { | 154 | pub fn len(&self) -> usize { |
106 | self.roots.len() | 155 | self.roots.len() |
107 | } | 156 | } |
157 | |||
158 | /// Add a new set of paths prefixes. | ||
108 | pub fn add_file_set(&mut self, roots: Vec<VfsPath>) { | 159 | pub fn add_file_set(&mut self, roots: Vec<VfsPath>) { |
109 | self.roots.push(roots) | 160 | self.roots.push(roots) |
110 | } | 161 | } |
162 | |||
163 | /// Build the `FileSetConfig`. | ||
111 | pub fn build(self) -> FileSetConfig { | 164 | pub fn build(self) -> FileSetConfig { |
112 | let n_file_sets = self.roots.len() + 1; | 165 | let n_file_sets = self.roots.len() + 1; |
113 | let map = { | 166 | let map = { |
@@ -127,11 +180,15 @@ impl FileSetConfigBuilder { | |||
127 | } | 180 | } |
128 | } | 181 | } |
129 | 182 | ||
183 | /// Implements [`fst::Automaton`] | ||
184 | /// | ||
185 | /// It will match if `prefix_of` is a prefix of the given data. | ||
130 | struct PrefixOf<'a> { | 186 | struct PrefixOf<'a> { |
131 | prefix_of: &'a [u8], | 187 | prefix_of: &'a [u8], |
132 | } | 188 | } |
133 | 189 | ||
134 | impl<'a> PrefixOf<'a> { | 190 | impl<'a> PrefixOf<'a> { |
191 | /// Creates a new `PrefixOf` from the given slice. | ||
135 | fn new(prefix_of: &'a [u8]) -> Self { | 192 | fn new(prefix_of: &'a [u8]) -> Self { |
136 | Self { prefix_of } | 193 | Self { prefix_of } |
137 | } | 194 | } |