From 3c30722a06d60c35c40b46634cb2b52fb8ee0d2e Mon Sep 17 00:00:00 2001
From: Jiahao XU <Jiahao_XU@outlook.com>
Date: Sun, 12 Jun 2022 01:57:34 +1000
Subject: [PATCH] Impl new type `Vfs` which impl `AbstractFilesystem`

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
---
 src/drivers.rs     |  2 ++
 src/drivers/vfs.rs | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 src/drivers/vfs.rs

diff --git a/src/drivers.rs b/src/drivers.rs
index c63d3044..5b053f25 100644
--- a/src/drivers.rs
+++ b/src/drivers.rs
@@ -8,6 +8,8 @@ pub use cratesio::*;
 mod version;
 use version::find_version;
 
+mod vfs;
+
 /// Fetch a crate by name and version from github
 /// TODO: implement this
 pub async fn fetch_crate_gh_releases(
diff --git a/src/drivers/vfs.rs b/src/drivers/vfs.rs
new file mode 100644
index 00000000..0051c44e
--- /dev/null
+++ b/src/drivers/vfs.rs
@@ -0,0 +1,39 @@
+use std::collections::{hash_map::HashMap, hash_set::HashSet};
+use std::io;
+use std::path::Path;
+
+use cargo_toml::AbstractFilesystem;
+
+use crate::helpers::PathExt;
+
+#[derive(Debug)]
+pub(super) struct Vfs(HashMap<Box<Path>, HashSet<Box<str>>>);
+
+impl Vfs {
+    pub(super) fn new() -> Self {
+        Self(HashMap::with_capacity(16))
+    }
+
+    /// * `path` - must be canonical, must not be empty and must
+    ///   start with a prefix.
+    pub(super) fn add_path(&mut self, mut path: &Path) {
+        while let Some(parent) = path.parent() {
+            if let Some(path_str) = path.to_str() {
+                self.0
+                    .entry(parent.into())
+                    .or_insert_with(|| HashSet::with_capacity(4))
+                    .insert(path_str.into());
+            }
+
+            path = parent;
+        }
+    }
+}
+
+impl AbstractFilesystem for Vfs {
+    fn file_names_in(&self, rel_path: &str) -> io::Result<HashSet<Box<str>>> {
+        let rel_path = Path::new(rel_path).normalize_path();
+
+        Ok(self.0.get(&*rel_path).map(Clone::clone).unwrap_or_default())
+    }
+}