Switch worktree entries to HashMap

Nathan Sobo created

Change summary

zed/src/worktree/worktree.rs | 68 ++++++++++++++++++++-----------------
1 file changed, 37 insertions(+), 31 deletions(-)

Detailed changes

zed/src/worktree/worktree.rs 🔗

@@ -33,7 +33,7 @@ pub struct Worktree(Arc<RwLock<WorktreeState>>);
 struct WorktreeState {
     id: usize,
     path: PathBuf,
-    entries: Vec<Entry>,
+    entries: HashMap<usize, Entry>,
     file_paths: Vec<PathEntry>,
     histories: HashMap<usize, History>,
     scanning: bool,
@@ -55,7 +55,7 @@ impl Worktree {
         let tree = Self(Arc::new(RwLock::new(WorktreeState {
             id,
             path: path.into(),
-            entries: Vec::new(),
+            entries: HashMap::new(),
             file_paths: Vec::new(),
             histories: HashMap::new(),
             scanning: ctx.is_some(),
@@ -102,7 +102,7 @@ impl Worktree {
 
         if metadata.file_type().is_dir() {
             let is_ignored = is_ignored || name == ".git";
-            let id = self.push_dir(None, name, ino, is_symlink, is_ignored);
+            let id = self.insert_dir(None, name, ino, is_symlink, is_ignored);
             let (tx, rx) = channel::unbounded();
 
             tx.send(Ok(DirToScan {
@@ -110,7 +110,6 @@ impl Worktree {
                 path,
                 relative_path,
                 ignore: Some(ignore),
-                dirs_to_scan: tx_,
                 dirs_to_scan: tx.clone(),
             }))
             .unwrap();
@@ -127,7 +126,7 @@ impl Worktree {
                 .into_iter()
                 .collect::<io::Result<()>>()?;
         } else {
-            self.push_file(None, name, ino, is_symlink, is_ignored, relative_path);
+            self.insert_file(None, name, ino, is_symlink, is_ignored, relative_path);
         }
 
         Ok(())
@@ -157,7 +156,7 @@ impl Worktree {
                     }
                 }
 
-                let id = self.push_dir(Some(to_scan.id), name, ino, is_symlink, is_ignored);
+                let id = self.insert_dir(Some(to_scan.id), name, ino, is_symlink, is_ignored);
                 new_children.push(id);
 
                 let dirs_to_scan = to_scan.dirs_to_scan.clone();
@@ -173,7 +172,7 @@ impl Worktree {
                     i.matched(to_scan.path.join(&name), false).is_ignore()
                 });
 
-                new_children.push(self.push_file(
+                new_children.push(self.insert_file(
                     Some(to_scan.id),
                     name,
                     ino,
@@ -184,14 +183,15 @@ impl Worktree {
             };
         }
 
-        if let Entry::Dir { children, .. } = &mut self.0.write().entries[to_scan.id] {
+        if let Some(Entry::Dir { children, .. }) = &mut self.0.write().entries.get_mut(&to_scan.id)
+        {
             *children = new_children.clone();
         }
 
         Ok(())
     }
 
-    fn push_dir(
+    fn insert_dir(
         &self,
         parent: Option<usize>,
         name: OsString,
@@ -201,18 +201,21 @@ impl Worktree {
     ) -> usize {
         let entries = &mut self.0.write().entries;
         let dir_id = entries.len();
-        entries.push(Entry::Dir {
-            parent,
-            name,
-            ino,
-            is_symlink,
-            is_ignored,
-            children: Vec::new(),
-        });
+        entries.insert(
+            dir_id,
+            Entry::Dir {
+                parent,
+                name,
+                ino,
+                is_symlink,
+                is_ignored,
+                children: Vec::new(),
+            },
+        );
         dir_id
     }
 
-    fn push_file(
+    fn insert_file(
         &self,
         parent: Option<usize>,
         name: OsString,
@@ -228,13 +231,16 @@ impl Worktree {
 
         let mut state = self.0.write();
         let entry_id = state.entries.len();
-        state.entries.push(Entry::File {
-            parent,
-            name,
-            ino,
-            is_symlink,
-            is_ignored,
-        });
+        state.entries.insert(
+            entry_id,
+            Entry::File {
+                parent,
+                name,
+                ino,
+                is_symlink,
+                is_ignored,
+            },
+        );
         state.file_paths.push(PathEntry {
             entry_id,
             path_chars,
@@ -254,7 +260,7 @@ impl Worktree {
 
         let mut entries = Vec::new();
         loop {
-            let entry = &state.entries[entry_id];
+            let entry = &state.entries[&entry_id];
             entries.push(entry);
             if let Some(parent_id) = entry.parent() {
                 entry_id = parent_id;
@@ -277,7 +283,7 @@ impl Worktree {
     }
 
     fn fmt_entry(&self, f: &mut fmt::Formatter<'_>, entry_id: usize, indent: usize) -> fmt::Result {
-        match &self.0.read().entries[entry_id] {
+        match &self.0.read().entries[&entry_id] {
             Entry::Dir { name, children, .. } => {
                 write!(
                     f,
@@ -498,7 +504,7 @@ impl Iterator for Iter {
         if !self.started {
             self.started = true;
 
-            return if let Some(entry) = state.entries.first().cloned() {
+            return if let Some(entry) = state.entries.get(&0).cloned() {
                 self.stack.push(IterStackEntry {
                     entry_id: 0,
                     child_idx: 0,
@@ -511,7 +517,7 @@ impl Iterator for Iter {
         }
 
         while let Some(parent) = self.stack.last_mut() {
-            if let Entry::Dir { children, .. } = &state.entries[parent.entry_id] {
+            if let Entry::Dir { children, .. } = &state.entries[&parent.entry_id] {
                 if parent.child_idx < children.len() {
                     let child_id = children[post_inc(&mut parent.child_idx)];
 
@@ -522,7 +528,7 @@ impl Iterator for Iter {
 
                     return Some(Traversal::Push {
                         entry_id: child_id,
-                        entry: state.entries[child_id].clone(),
+                        entry: state.entries[&child_id].clone(),
                     });
                 } else {
                     self.stack.pop();
@@ -614,7 +620,7 @@ pub fn match_paths(
             .iter()
             .map(|tree| {
                 let skip_prefix = if trees.len() == 1 {
-                    if let Some(Entry::Dir { name, .. }) = tree.entries.get(0) {
+                    if let Some(Entry::Dir { name, .. }) = tree.entries.get(&0) {
                         let name = name.to_string_lossy();
                         if name == "/" {
                             1