From e336a96998710c94685d42435acccff15dc8cd4f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Jul 2020 09:06:51 +0200 Subject: FileSetConfig works with empty set of roots Closes #5139 --- crates/vfs/src/file_set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index d0ddeafe7..977ba3010 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs @@ -69,7 +69,7 @@ impl FileSetConfig { Ok(it) => it, Err(it) => it.saturating_sub(1), }; - if path.starts_with(&self.roots[idx].0) { + if !self.roots.is_empty() && path.starts_with(&self.roots[idx].0) { self.roots[idx].1 } else { self.len() - 1 -- cgit v1.2.3 From 5d2225f4bc82c4cd551db5a53500e7a076bf5586 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 7 Jul 2020 17:38:02 +0200 Subject: Fix symbol search in salsa Previous solution for binning paths into disjoint directories was simple and fast -- just a single binary search. Unfortunatelly, it wasn't coorrect: if the ditr are /d /d/a /d/c then partitioning the file /d/b/lib.rs won't pick /d as a correct directory. The correct solution here is a trie, but it requires exposing path components. So, we use a poor man's substitution -- a *vector* of sorted paths, such that each bucket is prefix-free closes #5246 --- crates/vfs/src/file_set.rs | 109 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 19 deletions(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index 977ba3010..b0130017e 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs @@ -2,7 +2,7 @@ //! //! Files which do not belong to any explicitly configured `FileSet` belong to //! the default `FileSet`. -use std::{fmt, iter}; +use std::{fmt, mem}; use rustc_hash::FxHashMap; @@ -15,6 +15,9 @@ pub struct FileSet { } impl FileSet { + pub fn len(&self) -> usize { + self.files.len() + } pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option { let mut base = self.paths[&anchor].clone(); base.pop(); @@ -37,10 +40,15 @@ impl fmt::Debug for FileSet { } } +// Invariant: if k1 is a prefix of k2, then they are in different buckets (k2 +// is closer to 0th bucket). +// FIXME: replace with an actual trie some day. +type BadTrie = Vec>; + #[derive(Debug)] pub struct FileSetConfig { n_file_sets: usize, - roots: Vec<(VfsPath, usize)>, + trie: BadTrie, } impl Default for FileSetConfig { @@ -65,15 +73,7 @@ impl FileSetConfig { self.n_file_sets } fn classify(&self, path: &VfsPath) -> usize { - let idx = match self.roots.binary_search_by(|(p, _)| p.cmp(path)) { - Ok(it) => it, - Err(it) => it.saturating_sub(1), - }; - if !self.roots.is_empty() && path.starts_with(&self.roots[idx].0) { - self.roots[idx].1 - } else { - self.len() - 1 - } + find_ancestor(&self.trie, path, is_prefix).copied().unwrap_or(self.len() - 1) } } @@ -96,13 +96,84 @@ impl FileSetConfigBuilder { } pub fn build(self) -> FileSetConfig { let n_file_sets = self.roots.len() + 1; - let mut roots: Vec<(VfsPath, usize)> = self - .roots - .into_iter() - .enumerate() - .flat_map(|(i, paths)| paths.into_iter().zip(iter::repeat(i))) - .collect(); - roots.sort(); - FileSetConfig { n_file_sets, roots } + + let mut trie = BadTrie::new(); + + for (i, paths) in self.roots.into_iter().enumerate() { + for p in paths { + insert(&mut trie, p, i, is_prefix); + } + } + trie.iter_mut().for_each(|it| it.sort()); + FileSetConfig { n_file_sets, trie } + } +} + +fn is_prefix(short: &VfsPath, long: &VfsPath) -> bool { + long.starts_with(short) +} + +fn insert bool>( + trie: &mut BadTrie, + mut key: K, + mut value: V, + is_prefix: P, +) { + 'outer: for level in 0.. { + if trie.len() == level { + trie.push(Vec::new()) + } + for (k, v) in trie[level].iter_mut() { + if is_prefix(&key, k) { + continue 'outer; + } + if is_prefix(k, &key) { + mem::swap(k, &mut key); + mem::swap(v, &mut value); + continue 'outer; + } + } + trie[level].push((key, value)); + return; + } +} + +fn find_ancestor<'t, K: Ord, V, P: Fn(&K, &K) -> bool>( + trie: &'t BadTrie, + key: &K, + is_prefix: P, +) -> Option<&'t V> { + for bucket in trie { + let idx = match bucket.binary_search_by(|(k, _)| k.cmp(key)) { + Ok(it) => it, + Err(it) => it.saturating_sub(1), + }; + if !bucket.is_empty() && is_prefix(&bucket[idx].0, key) { + return Some(&bucket[idx].1); + } } + None +} + +#[test] +fn test_partitioning() { + let mut file_set = FileSetConfig::builder(); + file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]); + file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]); + let file_set = file_set.build(); + + let mut vfs = Vfs::default(); + vfs.set_file_contents(VfsPath::new_virtual_path("/foo/src/lib.rs".into()), Some(Vec::new())); + vfs.set_file_contents( + VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()), + Some(Vec::new()), + ); + vfs.set_file_contents( + VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()), + Some(Vec::new()), + ); + vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new())); + + let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::>(); + assert_eq!(partition, vec![2, 1, 1]); } -- cgit v1.2.3 From 69b79e3a73f9a1b820cf6d5ebc9968d8b08d4e68 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 7 Jul 2020 22:53:12 +0200 Subject: Replace ad hocery with science --- crates/vfs/Cargo.toml | 1 + crates/vfs/src/file_set.rs | 105 +++++++++++++++++++++------------------------ crates/vfs/src/vfs_path.rs | 31 +++++++++++++ 3 files changed, 81 insertions(+), 56 deletions(-) (limited to 'crates/vfs') diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index 263069002..b985c4c10 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -6,5 +6,6 @@ edition = "2018" [dependencies] rustc-hash = "1.0" +fst = "0.4" paths = { path = "../paths" } diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index b0130017e..37c479306 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs @@ -2,8 +2,9 @@ //! //! Files which do not belong to any explicitly configured `FileSet` belong to //! the default `FileSet`. -use std::{fmt, mem}; +use std::fmt; +use fst::{IntoStreamer, Streamer}; use rustc_hash::FxHashMap; use crate::{FileId, Vfs, VfsPath}; @@ -40,15 +41,10 @@ impl fmt::Debug for FileSet { } } -// Invariant: if k1 is a prefix of k2, then they are in different buckets (k2 -// is closer to 0th bucket). -// FIXME: replace with an actual trie some day. -type BadTrie = Vec>; - #[derive(Debug)] pub struct FileSetConfig { n_file_sets: usize, - trie: BadTrie, + map: fst::Map>, } impl Default for FileSetConfig { @@ -62,9 +58,10 @@ impl FileSetConfig { FileSetConfigBuilder::default() } pub fn partition(&self, vfs: &Vfs) -> Vec { + let mut scratch_space = Vec::new(); let mut res = vec![FileSet::default(); self.len()]; for (file_id, path) in vfs.iter() { - let root = self.classify(&path); + let root = self.classify(&path, &mut scratch_space); res[root].insert(file_id, path) } res @@ -72,8 +69,16 @@ impl FileSetConfig { fn len(&self) -> usize { self.n_file_sets } - fn classify(&self, path: &VfsPath) -> usize { - find_ancestor(&self.trie, path, is_prefix).copied().unwrap_or(self.len() - 1) + fn classify(&self, path: &VfsPath, scratch_space: &mut Vec) -> usize { + scratch_space.clear(); + path.encode(scratch_space); + let automaton = PrefixOf::new(scratch_space.as_slice()); + let mut longest_prefix = self.len() - 1; + let mut stream = self.map.search(automaton).into_stream(); + while let Some((_, v)) = stream.next() { + longest_prefix = v as usize; + } + longest_prefix } } @@ -96,63 +101,51 @@ impl FileSetConfigBuilder { } pub fn build(self) -> FileSetConfig { let n_file_sets = self.roots.len() + 1; - - let mut trie = BadTrie::new(); - - for (i, paths) in self.roots.into_iter().enumerate() { - for p in paths { - insert(&mut trie, p, i, is_prefix); + let map = { + let mut entries = Vec::new(); + for (i, paths) in self.roots.into_iter().enumerate() { + for p in paths { + let mut buf = Vec::new(); + p.encode(&mut buf); + entries.push((buf, i as u64)); + } } - } - trie.iter_mut().for_each(|it| it.sort()); - FileSetConfig { n_file_sets, trie } + entries.sort(); + entries.dedup_by(|(a, _), (b, _)| a == b); + fst::Map::from_iter(entries).unwrap() + }; + FileSetConfig { n_file_sets, map } } } -fn is_prefix(short: &VfsPath, long: &VfsPath) -> bool { - long.starts_with(short) +struct PrefixOf<'a> { + prefix_of: &'a [u8], } -fn insert bool>( - trie: &mut BadTrie, - mut key: K, - mut value: V, - is_prefix: P, -) { - 'outer: for level in 0.. { - if trie.len() == level { - trie.push(Vec::new()) - } - for (k, v) in trie[level].iter_mut() { - if is_prefix(&key, k) { - continue 'outer; - } - if is_prefix(k, &key) { - mem::swap(k, &mut key); - mem::swap(v, &mut value); - continue 'outer; - } - } - trie[level].push((key, value)); - return; +impl<'a> PrefixOf<'a> { + fn new(prefix_of: &'a [u8]) -> Self { + Self { prefix_of } } } -fn find_ancestor<'t, K: Ord, V, P: Fn(&K, &K) -> bool>( - trie: &'t BadTrie, - key: &K, - is_prefix: P, -) -> Option<&'t V> { - for bucket in trie { - let idx = match bucket.binary_search_by(|(k, _)| k.cmp(key)) { - Ok(it) => it, - Err(it) => it.saturating_sub(1), - }; - if !bucket.is_empty() && is_prefix(&bucket[idx].0, key) { - return Some(&bucket[idx].1); +impl fst::Automaton for PrefixOf<'_> { + type State = usize; + fn start(&self) -> usize { + 0 + } + fn is_match(&self, &state: &usize) -> bool { + state != !0 + } + fn can_match(&self, &state: &usize) -> bool { + state != !0 + } + fn accept(&self, &state: &usize, byte: u8) -> usize { + if self.prefix_of.get(state) == Some(&byte) { + state + 1 + } else { + !0 } } - None } #[test] diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs index dc3031ada..04a42264e 100644 --- a/crates/vfs/src/vfs_path.rs +++ b/crates/vfs/src/vfs_path.rs @@ -48,6 +48,37 @@ impl VfsPath { (VfsPathRepr::VirtualPath(_), _) => false, } } + + // Don't make this `pub` + pub(crate) fn encode(&self, buf: &mut Vec) { + let tag = match &self.0 { + VfsPathRepr::PathBuf(_) => 0, + VfsPathRepr::VirtualPath(_) => 1, + }; + buf.push(tag); + match &self.0 { + VfsPathRepr::PathBuf(it) => { + let path: &std::ffi::OsStr = it.as_os_str(); + #[cfg(windows)] + { + use std::os::windows::ffi::OsStrExt; + for wchar in path.encode_wide() { + buf.extend(wchar.to_le_bytes().iter().copied()); + } + } + #[cfg(unix)] + { + use std::os::unix::ffi::OsStrExt; + buf.extend(path.as_bytes()); + } + #[cfg(not(any(windows, unix)))] + { + buf.extend(path.to_string_lossy().as_bytes()); + } + } + VfsPathRepr::VirtualPath(VirtualPath(s)) => buf.extend(s.as_bytes()), + } + } } #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -- cgit v1.2.3 From 86bc4d20b30b8deb7783c200ad9f5d3acf019116 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Jul 2020 18:48:39 +0200 Subject: Also reload when adding new examples, tests, etc --- crates/vfs/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 024e58018..569da8a1c 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -70,7 +70,7 @@ impl ChangedFile { } } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, Copy, Clone)] pub enum ChangeKind { Create, Modify, -- cgit v1.2.3 From a1ef6cc553bbd141d94144ccb8e1599fa3f76526 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 10 Jul 2020 22:29:40 +0200 Subject: Optimize VFS processing --- crates/vfs/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 569da8a1c..3bfecd08f 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -70,7 +70,7 @@ impl ChangedFile { } } -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum ChangeKind { Create, Modify, -- cgit v1.2.3 From 847135495fb194f9eef7b65b515982161d77face Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 11 Jul 2020 13:31:02 +0200 Subject: no doctests --- crates/vfs/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) (limited to 'crates/vfs') diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index b985c4c10..db99707b3 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" authors = ["rust-analyzer developers"] edition = "2018" +[lib] +doctest = false + [dependencies] rustc-hash = "1.0" fst = "0.4" -- cgit v1.2.3 From 6f423466d181130848c229e2684c6dd18f8a5e9d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 14 Jul 2020 10:57:26 +0900 Subject: Add a license field to all the crates --- crates/vfs/Cargo.toml | 1 + 1 file changed, 1 insertion(+) (limited to 'crates/vfs') diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index db99707b3..b74cdb7ff 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -3,6 +3,7 @@ name = "vfs" version = "0.1.0" authors = ["rust-analyzer developers"] edition = "2018" +license = "MIT OR Apache-2.0" [lib] doctest = false -- cgit v1.2.3 From dc2094cfa5b15bb5b915c5f1ba81535e45d0af22 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 14 Jul 2020 15:57:10 +0200 Subject: Minor, push allocations down --- crates/vfs/src/file_set.rs | 2 +- crates/vfs/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index 37c479306..e5e2ef530 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs @@ -62,7 +62,7 @@ impl FileSetConfig { let mut res = vec![FileSet::default(); self.len()]; for (file_id, path) in vfs.iter() { let root = self.classify(&path, &mut scratch_space); - res[root].insert(file_id, path) + res[root].insert(file_id, path.clone()) } res } diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 3bfecd08f..cdf6f1fd0 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -90,12 +90,12 @@ impl Vfs { pub fn file_contents(&self, file_id: FileId) -> &[u8] { self.get(file_id).as_deref().unwrap() } - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { (0..self.data.len()) .map(|it| FileId(it as u32)) .filter(move |&file_id| self.get(file_id).is_some()) .map(move |file_id| { - let path = self.interner.lookup(file_id).clone(); + let path = self.interner.lookup(file_id); (file_id, path) }) } -- cgit v1.2.3 From 46ac9ff5e3cf070584d8167150655d091d47e3c2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 18 Jul 2020 16:40:10 +0200 Subject: Simplify exclusion logic --- crates/vfs/src/loader.rs | 82 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 9 deletions(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs index 6de2e5b3f..9c6e4b6a7 100644 --- a/crates/vfs/src/loader.rs +++ b/crates/vfs/src/loader.rs @@ -3,10 +3,25 @@ use std::fmt; use paths::{AbsPath, AbsPathBuf}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Entry { Files(Vec), - Directory { path: AbsPathBuf, include: Vec }, + Directories(Directories), +} + +/// Specifies a set of files on the file system. +/// +/// A file is included if: +/// * it has included extension +/// * it is under an `include` path +/// * it is not under `exclude` path +/// +/// If many include/exclude paths match, the longest one wins. +#[derive(Debug, Clone)] +pub struct Directories { + pub extensions: Vec, + pub include: Vec, + pub exclude: Vec, } #[derive(Debug)] @@ -33,21 +48,70 @@ pub trait Handle: fmt::Debug { impl Entry { pub fn rs_files_recursively(base: AbsPathBuf) -> Entry { - Entry::Directory { path: base, include: globs(&["*.rs", "!/.git/"]) } + Entry::Directories(dirs(base, &[".git"])) } pub fn local_cargo_package(base: AbsPathBuf) -> Entry { - Entry::Directory { path: base, include: globs(&["*.rs", "!/target/", "!/.git/"]) } + Entry::Directories(dirs(base, &[".git", "target"])) } pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry { - Entry::Directory { - path: base, - include: globs(&["*.rs", "!/tests/", "!/examples/", "!/benches/", "!/.git/"]), + Entry::Directories(dirs(base, &[".git", "/tests", "/examples", "/benches"])) + } + + pub fn contains_file(&self, path: &AbsPath) -> bool { + match self { + Entry::Files(files) => files.iter().any(|it| it == path), + Entry::Directories(dirs) => dirs.contains_file(path), + } + } + pub fn contains_dir(&self, path: &AbsPath) -> bool { + match self { + Entry::Files(_) => false, + Entry::Directories(dirs) => dirs.contains_dir(path), + } + } +} + +impl Directories { + pub fn contains_file(&self, path: &AbsPath) -> bool { + let ext = path.extension().unwrap_or_default(); + if self.extensions.iter().all(|it| it.as_str() != ext) { + return false; + } + self.includes_path(path) + } + pub fn contains_dir(&self, path: &AbsPath) -> bool { + self.includes_path(path) + } + fn includes_path(&self, path: &AbsPath) -> bool { + let mut include = None; + for incl in &self.include { + if is_prefix(incl, path) { + include = Some(match include { + Some(prev) if is_prefix(incl, prev) => prev, + _ => incl, + }) + } + } + let include = match include { + Some(it) => it, + None => return false, + }; + for excl in &self.exclude { + if is_prefix(excl, path) && is_prefix(include, excl) { + return false; + } + } + return true; + + fn is_prefix(short: &AbsPath, long: &AbsPath) -> bool { + long.strip_prefix(short).is_some() } } } -fn globs(globs: &[&str]) -> Vec { - globs.iter().map(|it| it.to_string()).collect() +fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories { + let exclude = exclude.iter().map(|it| base.join(it)).collect::>(); + Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude } } impl fmt::Debug for Message { -- cgit v1.2.3 From 3e688d2a9340e8d8ca2da5bbdc441f2d6cce893c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 20 Jul 2020 18:01:42 +0200 Subject: Simplify --- crates/vfs/src/loader.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs index 9c6e4b6a7..04e257f53 100644 --- a/crates/vfs/src/loader.rs +++ b/crates/vfs/src/loader.rs @@ -83,11 +83,11 @@ impl Directories { self.includes_path(path) } fn includes_path(&self, path: &AbsPath) -> bool { - let mut include = None; + let mut include: Option<&AbsPathBuf> = None; for incl in &self.include { - if is_prefix(incl, path) { + if path.starts_with(incl) { include = Some(match include { - Some(prev) if is_prefix(incl, prev) => prev, + Some(prev) if prev.starts_with(incl) => prev, _ => incl, }) } @@ -97,15 +97,11 @@ impl Directories { None => return false, }; for excl in &self.exclude { - if is_prefix(excl, path) && is_prefix(include, excl) { + if path.starts_with(excl) && excl.starts_with(include) { return false; } } - return true; - - fn is_prefix(short: &AbsPath, long: &AbsPath) -> bool { - long.strip_prefix(short).is_some() - } + true } } -- cgit v1.2.3 From 39a2bc5e3cd86876eef6f3a96bef188f88e85114 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 21 Jul 2020 12:52:51 +0200 Subject: Expose package roots more directly --- crates/vfs/src/loader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs index 04e257f53..40cf96020 100644 --- a/crates/vfs/src/loader.rs +++ b/crates/vfs/src/loader.rs @@ -17,7 +17,7 @@ pub enum Entry { /// * it is not under `exclude` path /// /// If many include/exclude paths match, the longest one wins. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Directories { pub extensions: Vec, pub include: Vec, -- cgit v1.2.3 From da65cff18bbdf72be64525e639590dce41f6ff14 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 26 Jul 2020 11:05:28 +0200 Subject: Add one more test --- crates/vfs/src/file_set.rs | 71 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 21 deletions(-) (limited to 'crates/vfs') diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs index e5e2ef530..e9196fcd2 100644 --- a/crates/vfs/src/file_set.rs +++ b/crates/vfs/src/file_set.rs @@ -148,25 +148,54 @@ impl fst::Automaton for PrefixOf<'_> { } } -#[test] -fn test_partitioning() { - let mut file_set = FileSetConfig::builder(); - file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]); - file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]); - let file_set = file_set.build(); - - let mut vfs = Vfs::default(); - vfs.set_file_contents(VfsPath::new_virtual_path("/foo/src/lib.rs".into()), Some(Vec::new())); - vfs.set_file_contents( - VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()), - Some(Vec::new()), - ); - vfs.set_file_contents( - VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()), - Some(Vec::new()), - ); - vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new())); - - let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::>(); - assert_eq!(partition, vec![2, 1, 1]); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn path_prefix() { + let mut file_set = FileSetConfig::builder(); + file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]); + file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]); + let file_set = file_set.build(); + + let mut vfs = Vfs::default(); + vfs.set_file_contents( + VfsPath::new_virtual_path("/foo/src/lib.rs".into()), + Some(Vec::new()), + ); + vfs.set_file_contents( + VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()), + Some(Vec::new()), + ); + vfs.set_file_contents( + VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()), + Some(Vec::new()), + ); + vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new())); + + let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::>(); + assert_eq!(partition, vec![2, 1, 1]); + } + + #[test] + fn name_prefix() { + let mut file_set = FileSetConfig::builder(); + file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]); + file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo-things".into())]); + let file_set = file_set.build(); + + let mut vfs = Vfs::default(); + vfs.set_file_contents( + VfsPath::new_virtual_path("/foo/src/lib.rs".into()), + Some(Vec::new()), + ); + vfs.set_file_contents( + VfsPath::new_virtual_path("/foo-things/src/lib.rs".into()), + Some(Vec::new()), + ); + + let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::>(); + assert_eq!(partition, vec![1, 1, 0]); + } } -- cgit v1.2.3