Document vfs private items
This commit is contained in:
parent
311ec70d03
commit
4b71c8332d
@ -83,7 +83,12 @@ impl fmt::Debug for FileSet {
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct FileSetConfig {
|
||||
/// Number of sets that `self` can partition a [`Vfs`] into.
|
||||
///
|
||||
/// This should be the number of sets in `self.map` + 1 for files that don't fit in any
|
||||
/// defined set.
|
||||
n_file_sets: usize,
|
||||
/// Map from encoded paths to the set they belong to.
|
||||
map: fst::Map<Vec<u8>>,
|
||||
}
|
||||
|
||||
@ -111,9 +116,15 @@ impl FileSetConfig {
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/// Number of sets that `self` can partition a [`Vfs`] into.
|
||||
fn len(&self) -> usize {
|
||||
self.n_file_sets
|
||||
}
|
||||
|
||||
/// Returns the set index for the given `path`.
|
||||
///
|
||||
/// `scratch_space` is used as a buffer and will be entirely replaced.
|
||||
fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize {
|
||||
scratch_space.clear();
|
||||
path.encode(scratch_space);
|
||||
@ -169,11 +180,15 @@ impl FileSetConfigBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements [`fst::Automaton`]
|
||||
///
|
||||
/// It will match if `prefix_of` is a prefix of the given data.
|
||||
struct PrefixOf<'a> {
|
||||
prefix_of: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> PrefixOf<'a> {
|
||||
/// Creates a new `PrefixOf` from the given slice.
|
||||
fn new(prefix_of: &'a [u8]) -> Self {
|
||||
Self { prefix_of }
|
||||
}
|
||||
|
@ -176,6 +176,14 @@ impl Vfs {
|
||||
pub fn take_changes(&mut self) -> Vec<ChangedFile> {
|
||||
mem::take(&mut self.changes)
|
||||
}
|
||||
|
||||
/// Returns the id associated with `path`
|
||||
///
|
||||
/// - If `path` does not exists in the `Vfs`, allocate a new id for it, associated with a
|
||||
/// deleted file;
|
||||
/// - Else, returns `path`'s id.
|
||||
///
|
||||
/// Does not record a change.
|
||||
fn alloc_file_id(&mut self, path: VfsPath) -> FileId {
|
||||
let file_id = self.interner.intern(path);
|
||||
let idx = file_id.0 as usize;
|
||||
@ -183,9 +191,21 @@ impl Vfs {
|
||||
self.data.resize_with(len, || None);
|
||||
file_id
|
||||
}
|
||||
|
||||
/// Returns the content associated with the given `file_id`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if no file is associated to that id.
|
||||
fn get(&self, file_id: FileId) -> &Option<Vec<u8>> {
|
||||
&self.data[file_id.0 as usize]
|
||||
}
|
||||
|
||||
/// Mutably returns the content associated with the given `file_id`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if no file is associated to that id.
|
||||
fn get_mut(&mut self, file_id: FileId) -> &mut Option<Vec<u8>> {
|
||||
&mut self.data[file_id.0 as usize]
|
||||
}
|
||||
|
@ -147,6 +147,13 @@ impl Directories {
|
||||
pub fn contains_dir(&self, path: &AbsPath) -> bool {
|
||||
self.includes_path(path)
|
||||
}
|
||||
|
||||
/// Returns `true` if `path` is included in `self`.
|
||||
///
|
||||
/// It is included if
|
||||
/// - An element in `self.include` is a prefix of `path`.
|
||||
/// - This path is longer than any element in `self.exclude` that is a prefix
|
||||
/// of `path`. In case of equality, exclusion wins.
|
||||
fn includes_path(&self, path: &AbsPath) -> bool {
|
||||
let mut include: Option<&AbsPathBuf> = None;
|
||||
for incl in &self.include {
|
||||
@ -170,6 +177,14 @@ impl Directories {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns :
|
||||
/// ```text
|
||||
/// Directories {
|
||||
/// extensions: ["rs"],
|
||||
/// include: [base],
|
||||
/// exclude: [base/<exclude>],
|
||||
/// }
|
||||
/// ```
|
||||
fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories {
|
||||
let exclude = exclude.iter().map(|it| base.join(it)).collect::<Vec<_>>();
|
||||
Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude }
|
||||
|
@ -5,6 +5,7 @@ use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{FileId, VfsPath};
|
||||
|
||||
/// Structure to map between [`VfsPath`] and [`FileId`].
|
||||
#[derive(Default)]
|
||||
pub(crate) struct PathInterner {
|
||||
map: FxHashMap<VfsPath, FileId>,
|
||||
@ -12,9 +13,17 @@ pub(crate) struct PathInterner {
|
||||
}
|
||||
|
||||
impl PathInterner {
|
||||
/// Get the id corresponding to `path`.
|
||||
///
|
||||
/// If `path` does not exists in `self`, returns [`None`].
|
||||
pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> {
|
||||
self.map.get(path).copied()
|
||||
}
|
||||
|
||||
/// Insert `path` in `self`.
|
||||
///
|
||||
/// - If `path` already exists in `self`, returns its associated id;
|
||||
/// - Else, returns a newly allocated id.
|
||||
pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
|
||||
if let Some(id) = self.get(&path) {
|
||||
return id;
|
||||
@ -25,6 +34,11 @@ impl PathInterner {
|
||||
id
|
||||
}
|
||||
|
||||
/// Returns the path corresponding to `id`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `id` does not exists in `self`.
|
||||
pub(crate) fn lookup(&self, id: FileId) -> &VfsPath {
|
||||
&self.vec[id.0 as usize]
|
||||
}
|
||||
|
@ -102,7 +102,14 @@ impl VfsPath {
|
||||
}
|
||||
}
|
||||
|
||||
// Don't make this `pub`
|
||||
/// **Don't make this `pub`**
|
||||
///
|
||||
/// Encode the path in the given buffer.
|
||||
///
|
||||
/// The encoding will be `0` if [`AbsPathBuf`], `1` if [`VirtualPath`], followed
|
||||
/// by `self`'s representation.
|
||||
///
|
||||
/// Note that this encoding is dependent on the operating system.
|
||||
pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
|
||||
let tag = match &self.0 {
|
||||
VfsPathRepr::PathBuf(_) => 0,
|
||||
@ -259,6 +266,7 @@ mod windows_paths {
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal, private representation of [`VfsPath`].
|
||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||
enum VfsPathRepr {
|
||||
PathBuf(AbsPathBuf),
|
||||
@ -295,13 +303,34 @@ impl fmt::Debug for VfsPathRepr {
|
||||
}
|
||||
}
|
||||
|
||||
/// `/`-separated virtual path.
|
||||
///
|
||||
/// This is used to describe files that do not reside on the file system.
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||
struct VirtualPath(String);
|
||||
|
||||
impl VirtualPath {
|
||||
/// Returns `true` if `other` is a prefix of `self` (as strings).
|
||||
fn starts_with(&self, other: &VirtualPath) -> bool {
|
||||
self.0.starts_with(&other.0)
|
||||
}
|
||||
|
||||
/// Remove the last component of `self`.
|
||||
///
|
||||
/// This will find the last `'/'` in `self`, and remove everything after it,
|
||||
/// including the `'/'`.
|
||||
///
|
||||
/// If `self` contains no `'/'`, returns `false`; else returns `true`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// let mut path = VirtualPath("/foo/bar".to_string());
|
||||
/// path.pop();
|
||||
/// assert_eq!(path.0, "/foo");
|
||||
/// path.pop();
|
||||
/// assert_eq!(path.0, "");
|
||||
/// ```
|
||||
fn pop(&mut self) -> bool {
|
||||
let pos = match self.0.rfind('/') {
|
||||
Some(pos) => pos,
|
||||
@ -310,6 +339,17 @@ impl VirtualPath {
|
||||
self.0 = self.0[..pos].to_string();
|
||||
true
|
||||
}
|
||||
|
||||
/// Append the given *relative* path `path` to `self`.
|
||||
///
|
||||
/// This will resolve any leading `"../"` in `path` before appending it.
|
||||
///
|
||||
/// Returns [`None`] if `path` has more leading `"../"` than the number of
|
||||
/// components in `self`.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// In practice, appending here means `self/path` as strings.
|
||||
fn join(&self, mut path: &str) -> Option<VirtualPath> {
|
||||
let mut res = self.clone();
|
||||
while path.starts_with("../") {
|
||||
@ -322,7 +362,18 @@ impl VirtualPath {
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub(crate) fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
|
||||
/// Returns `self`'s base name and file extension.
|
||||
///
|
||||
/// # Returns
|
||||
/// - `None` if `self` ends with `"//"`.
|
||||
/// - `Some((name, None))` if `self`'s base contains no `.`, or only one `.` at
|
||||
/// the start.
|
||||
/// - `Some((name, Some(extension))` else.
|
||||
///
|
||||
/// # Note
|
||||
/// The extension will not contains `.`. This means `"/foo/bar.baz.rs"` will
|
||||
/// return `Some(("bar.baz", Some("rs"))`.
|
||||
fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
|
||||
let file_path = if self.0.ends_with('/') { &self.0[..&self.0.len() - 1] } else { &self.0 };
|
||||
let file_name = match file_path.rfind('/') {
|
||||
Some(position) => &file_path[position + 1..],
|
||||
|
Loading…
x
Reference in New Issue
Block a user