rust/hg-core/src/dirstate/dirstate_tree/node.rs
changeset 46890 441024b279a6
parent 46889 8759e22f1649
child 46891 c6ceb5f27f97
--- a/rust/hg-core/src/dirstate/dirstate_tree/node.rs	Sun Sep 13 22:14:25 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,398 +0,0 @@
-// node.rs
-//
-// Copyright 2020, Raphaël Gomès <rgomes@octobus.net>
-//
-// This software may be used and distributed according to the terms of the
-// GNU General Public License version 2 or any later version.
-
-use super::iter::Iter;
-use crate::utils::hg_path::HgPathBuf;
-use crate::{DirstateEntry, EntryState, FastHashMap};
-
-/// Represents a filesystem directory in the dirstate tree
-#[derive(Debug, Default, Clone, PartialEq)]
-pub struct Directory {
-    /// Contains the old file information if it existed between changesets.
-    /// Happens if a file `foo` is marked as removed, removed from the
-    /// filesystem then a directory `foo` is created and at least one of its
-    /// descendents is added to Mercurial.
-    pub(super) was_file: Option<Box<File>>,
-    pub(super) children: FastHashMap<Vec<u8>, Node>,
-}
-
-/// Represents a filesystem file (or symlink) in the dirstate tree
-#[derive(Debug, Clone, PartialEq)]
-pub struct File {
-    /// Contains the old structure if it existed between changesets.
-    /// Happens all descendents of `foo` marked as removed and removed from
-    /// the filesystem, then a file `foo` is created and added to Mercurial.
-    pub(super) was_directory: Option<Box<Directory>>,
-    pub(super) entry: DirstateEntry,
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum NodeKind {
-    Directory(Directory),
-    File(File),
-}
-
-#[derive(Debug, Default, Clone, PartialEq)]
-pub struct Node {
-    pub kind: NodeKind,
-}
-
-impl Default for NodeKind {
-    fn default() -> Self {
-        NodeKind::Directory(Default::default())
-    }
-}
-
-impl Node {
-    pub fn insert(
-        &mut self,
-        path: &[u8],
-        new_entry: DirstateEntry,
-    ) -> InsertResult {
-        let mut split = path.splitn(2, |&c| c == b'/');
-        let head = split.next().unwrap_or(b"");
-        let tail = split.next().unwrap_or(b"");
-
-        // Are we're modifying the current file ? Is the the end of the path ?
-        let is_current_file = tail.is_empty() && head.is_empty();
-
-        // Potentially Replace the current file with a directory if it's marked
-        // as `Removed`
-        if !is_current_file {
-            if let NodeKind::File(file) = &mut self.kind {
-                if file.entry.state == EntryState::Removed {
-                    self.kind = NodeKind::Directory(Directory {
-                        was_file: Some(Box::from(file.clone())),
-                        children: Default::default(),
-                    })
-                }
-            }
-        }
-        match &mut self.kind {
-            NodeKind::Directory(directory) => {
-                Node::insert_in_directory(directory, new_entry, head, tail)
-            }
-            NodeKind::File(file) => {
-                if is_current_file {
-                    let new = Self {
-                        kind: NodeKind::File(File {
-                            entry: new_entry,
-                            ..file.clone()
-                        }),
-                    };
-                    InsertResult {
-                        did_insert: false,
-                        old_entry: Some(std::mem::replace(self, new)),
-                    }
-                } else {
-                    match file.entry.state {
-                        EntryState::Removed => {
-                            unreachable!("Removed file turning into a directory was dealt with earlier")
-                        }
-                        _ => {
-                            Node::insert_in_file(
-                                file, new_entry, head, tail,
-                            )
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /// The current file still exists and is not marked as `Removed`.
-    /// Insert the entry in its `was_directory`.
-    fn insert_in_file(
-        file: &mut File,
-        new_entry: DirstateEntry,
-        head: &[u8],
-        tail: &[u8],
-    ) -> InsertResult {
-        if let Some(d) = &mut file.was_directory {
-            Node::insert_in_directory(d, new_entry, head, tail)
-        } else {
-            let mut dir = Directory {
-                was_file: None,
-                children: FastHashMap::default(),
-            };
-            let res =
-                Node::insert_in_directory(&mut dir, new_entry, head, tail);
-            file.was_directory = Some(Box::new(dir));
-            res
-        }
-    }
-
-    /// Insert an entry in the subtree of `directory`
-    fn insert_in_directory(
-        directory: &mut Directory,
-        new_entry: DirstateEntry,
-        head: &[u8],
-        tail: &[u8],
-    ) -> InsertResult {
-        let mut res = InsertResult::default();
-
-        if let Some(node) = directory.children.get_mut(head) {
-            // Node exists
-            match &mut node.kind {
-                NodeKind::Directory(subdir) => {
-                    if tail.is_empty() {
-                        let becomes_file = Self {
-                            kind: NodeKind::File(File {
-                                was_directory: Some(Box::from(subdir.clone())),
-                                entry: new_entry,
-                            }),
-                        };
-                        let old_entry = directory
-                            .children
-                            .insert(head.to_owned(), becomes_file);
-                        return InsertResult {
-                            did_insert: true,
-                            old_entry,
-                        };
-                    } else {
-                        res = node.insert(tail, new_entry);
-                    }
-                }
-                NodeKind::File(_) => {
-                    res = node.insert(tail, new_entry);
-                }
-            }
-        } else if tail.is_empty() {
-            // File does not already exist
-            directory.children.insert(
-                head.to_owned(),
-                Self {
-                    kind: NodeKind::File(File {
-                        was_directory: None,
-                        entry: new_entry,
-                    }),
-                },
-            );
-            res.did_insert = true;
-        } else {
-            // Directory does not already exist
-            let mut nested = Self {
-                kind: NodeKind::Directory(Directory {
-                    was_file: None,
-                    children: Default::default(),
-                }),
-            };
-            res = nested.insert(tail, new_entry);
-            directory.children.insert(head.to_owned(), nested);
-        }
-        res
-    }
-
-    /// Removes an entry from the tree, returns a `RemoveResult`.
-    pub fn remove(&mut self, path: &[u8]) -> RemoveResult {
-        let empty_result = RemoveResult::default();
-        if path.is_empty() {
-            return empty_result;
-        }
-        let mut split = path.splitn(2, |&c| c == b'/');
-        let head = split.next();
-        let tail = split.next().unwrap_or(b"");
-
-        let head = match head {
-            None => {
-                return empty_result;
-            }
-            Some(h) => h,
-        };
-        if head == path {
-            match &mut self.kind {
-                NodeKind::Directory(d) => {
-                    return Node::remove_from_directory(head, d);
-                }
-                NodeKind::File(f) => {
-                    if let Some(d) = &mut f.was_directory {
-                        let RemoveResult { old_entry, .. } =
-                            Node::remove_from_directory(head, d);
-                        return RemoveResult {
-                            cleanup: false,
-                            old_entry,
-                        };
-                    }
-                }
-            }
-            empty_result
-        } else {
-            // Look into the dirs
-            match &mut self.kind {
-                NodeKind::Directory(d) => {
-                    if let Some(child) = d.children.get_mut(head) {
-                        let mut res = child.remove(tail);
-                        if res.cleanup {
-                            d.children.remove(head);
-                        }
-                        res.cleanup =
-                            d.children.is_empty() && d.was_file.is_none();
-                        res
-                    } else {
-                        empty_result
-                    }
-                }
-                NodeKind::File(f) => {
-                    if let Some(d) = &mut f.was_directory {
-                        if let Some(child) = d.children.get_mut(head) {
-                            let RemoveResult { cleanup, old_entry } =
-                                child.remove(tail);
-                            if cleanup {
-                                d.children.remove(head);
-                            }
-                            if d.children.is_empty() && d.was_file.is_none() {
-                                f.was_directory = None;
-                            }
-
-                            return RemoveResult {
-                                cleanup: false,
-                                old_entry,
-                            };
-                        }
-                    }
-                    empty_result
-                }
-            }
-        }
-    }
-
-    fn remove_from_directory(head: &[u8], d: &mut Directory) -> RemoveResult {
-        if let Some(node) = d.children.get_mut(head) {
-            return match &mut node.kind {
-                NodeKind::Directory(d) => {
-                    if let Some(f) = &mut d.was_file {
-                        let entry = f.entry;
-                        d.was_file = None;
-                        RemoveResult {
-                            cleanup: false,
-                            old_entry: Some(entry),
-                        }
-                    } else {
-                        RemoveResult::default()
-                    }
-                }
-                NodeKind::File(f) => {
-                    let entry = f.entry;
-                    let mut cleanup = false;
-                    match &f.was_directory {
-                        None => {
-                            if d.children.len() == 1 {
-                                cleanup = true;
-                            }
-                            d.children.remove(head);
-                        }
-                        Some(dir) => {
-                            node.kind = NodeKind::Directory(*dir.clone());
-                        }
-                    }
-
-                    RemoveResult {
-                        cleanup,
-                        old_entry: Some(entry),
-                    }
-                }
-            };
-        }
-        RemoveResult::default()
-    }
-
-    pub fn get(&self, path: &[u8]) -> Option<&Node> {
-        if path.is_empty() {
-            return Some(&self);
-        }
-        let mut split = path.splitn(2, |&c| c == b'/');
-        let head = split.next();
-        let tail = split.next().unwrap_or(b"");
-
-        let head = match head {
-            None => {
-                return Some(&self);
-            }
-            Some(h) => h,
-        };
-        match &self.kind {
-            NodeKind::Directory(d) => {
-                if let Some(child) = d.children.get(head) {
-                    return child.get(tail);
-                }
-            }
-            NodeKind::File(f) => {
-                if let Some(d) = &f.was_directory {
-                    if let Some(child) = d.children.get(head) {
-                        return child.get(tail);
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
-    pub fn get_mut(&mut self, path: &[u8]) -> Option<&mut NodeKind> {
-        if path.is_empty() {
-            return Some(&mut self.kind);
-        }
-        let mut split = path.splitn(2, |&c| c == b'/');
-        let head = split.next();
-        let tail = split.next().unwrap_or(b"");
-
-        let head = match head {
-            None => {
-                return Some(&mut self.kind);
-            }
-            Some(h) => h,
-        };
-        match &mut self.kind {
-            NodeKind::Directory(d) => {
-                if let Some(child) = d.children.get_mut(head) {
-                    return child.get_mut(tail);
-                }
-            }
-            NodeKind::File(f) => {
-                if let Some(d) = &mut f.was_directory {
-                    if let Some(child) = d.children.get_mut(head) {
-                        return child.get_mut(tail);
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
-    pub fn iter(&self) -> Iter {
-        Iter::new(self)
-    }
-}
-
-/// Information returned to the caller of an `insert` operation for integrity.
-#[derive(Debug, Default)]
-pub struct InsertResult {
-    /// Whether the insertion resulted in an actual insertion and not an
-    /// update
-    pub(super) did_insert: bool,
-    /// The entry that was replaced, if it exists
-    pub(super) old_entry: Option<Node>,
-}
-
-/// Information returned to the caller of a `remove` operation integrity.
-#[derive(Debug, Default)]
-pub struct RemoveResult {
-    /// If the caller needs to remove the current node
-    pub(super) cleanup: bool,
-    /// The entry that was replaced, if it exists
-    pub(super) old_entry: Option<DirstateEntry>,
-}
-
-impl<'a> IntoIterator for &'a Node {
-    type Item = (HgPathBuf, DirstateEntry);
-    type IntoIter = Iter<'a>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.iter()
-    }
-}