D8049: rust-dirstatemap: add `NonNormalEntries` class

Alphare (Raphaël Gomès) phabricator at mercurial-scm.org
Thu Jan 30 14:10:17 UTC 2020


Alphare created this revision.
Herald added subscribers: mercurial-devel, kevincox.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  This fix introduces the same encapsulation as the `copymap`. There is no easy
  way of doing this any better for now.

REPOSITORY
  rHG Mercurial

BRANCH
  stable

REVISION DETAIL
  https://phab.mercurial-scm.org/D8049

AFFECTED FILES
  rust/hg-cpython/src/dirstate.rs
  rust/hg-cpython/src/dirstate/dirstate_map.rs
  rust/hg-cpython/src/dirstate/non_normal_entries.rs

CHANGE DETAILS

diff --git a/rust/hg-cpython/src/dirstate/non_normal_entries.rs b/rust/hg-cpython/src/dirstate/non_normal_entries.rs
new file mode 100644
--- /dev/null
+++ b/rust/hg-cpython/src/dirstate/non_normal_entries.rs
@@ -0,0 +1,52 @@
+// non_normal_other_parent_entries.rs
+//
+// Copyright 2020 Raphaël Gomès <rgomes at 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 cpython::{
+    exc::NotImplementedError, CompareOp, ObjectProtocol, PyErr, PyList,
+    PyObject, PyResult, PyString, Python, PythonObject, ToPyObject,
+};
+
+use crate::dirstate::DirstateMap;
+
+py_class!(pub class NonNormalEntries |py| {
+    data dmap: DirstateMap;
+
+    def __contains__(&self, key: PyObject) -> PyResult<bool> {
+        self.dmap(py).non_normal_entries_contains(py, key)
+    }
+    def remove(&self, key: PyObject) -> PyResult<PyObject> {
+        self.dmap(py).non_normal_entries_remove(py, key)
+    }
+    def union(&self, other: PyObject) -> PyResult<PyList> {
+        self.dmap(py).non_normal_entries_union(py, other)
+    }
+    def __richcmp__(&self, other: PyObject, op: CompareOp) -> PyResult<bool> {
+        match op {
+            CompareOp::Eq => self.is_equal_to(py, other),
+            CompareOp::Ne => Ok(!self.is_equal_to(py, other)?),
+            _ => Err(PyErr::new::<NotImplementedError, _>(py, ""))
+        }
+    }
+    def __repr__(&self) -> PyResult<PyString> {
+        self.dmap(py).non_normal_entries_display(py)
+    }
+});
+
+impl NonNormalEntries {
+    pub fn from_inner(py: Python, dm: DirstateMap) -> PyResult<Self> {
+        Self::create_instance(py, dm)
+    }
+
+    fn is_equal_to(&self, py: Python, other: PyObject) -> PyResult<bool> {
+        for item in other.iter(py)? {
+            if !self.dmap(py).non_normal_entries_contains(py, item?)? {
+                return Ok(false);
+            }
+        }
+        Ok(true)
+    }
+}
diff --git a/rust/hg-cpython/src/dirstate/dirstate_map.rs b/rust/hg-cpython/src/dirstate/dirstate_map.rs
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs
@@ -13,12 +13,13 @@
 use std::time::Duration;
 
 use cpython::{
-    exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject,
-    PyResult, PyTuple, Python, PythonObject, ToPyObject,
+    exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
+    PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
 };
 
 use crate::{
     dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
+    dirstate::non_normal_entries::NonNormalEntries,
     dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
     ref_sharing::{PyLeaked, PySharedRefCell},
 };
@@ -168,32 +169,86 @@
         Ok(py.None())
     }
 
-    // TODO share the reference
-    def nonnormalentries(&self) -> PyResult<PyObject> {
-        let (non_normal, other_parent) =
-            self.inner_shared(py).borrow().non_normal_other_parent_entries();
+    def other_parent_entries(&self) -> PyResult<PyObject> {
+        let mut inner_shared = self.inner_shared(py).borrow_mut()?;
+        let (_, other_parent) =
+            inner_shared.get_non_normal_other_parent_entries();
 
         let locals = PyDict::new(py);
         locals.set_item(
             py,
-            "non_normal",
-            non_normal
-                .iter()
-                .map(|v| PyBytes::new(py, v.as_ref()))
-                .collect::<Vec<PyBytes>>()
-                .to_py_object(py),
-        )?;
-        locals.set_item(
-            py,
             "other_parent",
-            other_parent
+            other_parent.as_ref()
+                .unwrap()
                 .iter()
                 .map(|v| PyBytes::new(py, v.as_ref()))
                 .collect::<Vec<PyBytes>>()
                 .to_py_object(py),
         )?;
 
-        py.eval("set(non_normal), set(other_parent)", None, Some(&locals))
+        py.eval("set(other_parent)", None, Some(&locals))
+    }
+
+    def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
+        NonNormalEntries::from_inner(py, self.clone_ref(py))
+    }
+
+    def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
+        let key = key.extract::<PyBytes>(py)?;
+        Ok(self
+            .inner_shared(py)
+            .borrow_mut()?
+            .get_non_normal_other_parent_entries().0
+            .as_ref()
+            .unwrap()
+            .contains(HgPath::new(key.data(py))))
+    }
+
+    def non_normal_entries_display(&self) -> PyResult<PyString> {
+        Ok(
+            PyString::new(
+                py,
+                &format!(
+                    "NonNormalEntries: {:?}",
+                    self
+                        .inner_shared(py)
+                        .borrow_mut()?
+                        .get_non_normal_other_parent_entries().0
+                        .as_ref()
+                        .unwrap().iter().map(|o| o))
+                )
+            )
+    }
+
+    def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
+        let key = key.extract::<PyBytes>(py)?;
+        self
+            .inner_shared(py)
+            .borrow_mut()?
+            .non_normal_entries_remove(HgPath::new(key.data(py)));
+        Ok(py.None())
+    }
+
+    def non_normal_entries_union(&self, other: PyObject) -> PyResult<PyList> {
+        let other: PyResult<_> = other.iter(py)?
+                    .map(|f| {
+                        Ok(HgPathBuf::from_bytes(
+                            f?.extract::<PyBytes>(py)?.data(py),
+                        ))
+                    })
+                    .collect();
+
+        let res = self
+            .inner_shared(py)
+            .borrow_mut()?
+            .non_normal_entries_union(other?);
+
+        let ret = PyList::new(py, &[]);
+        for (i, filename) in res.iter().enumerate() {
+            let as_pystring = PyBytes::new(py, filename.as_bytes());
+            ret.insert_item(py, i, as_pystring.into_object());
+        }
+        Ok(ret)
     }
 
     def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
diff --git a/rust/hg-cpython/src/dirstate.rs b/rust/hg-cpython/src/dirstate.rs
--- a/rust/hg-cpython/src/dirstate.rs
+++ b/rust/hg-cpython/src/dirstate.rs
@@ -12,6 +12,7 @@
 mod copymap;
 mod dirs_multiset;
 mod dirstate_map;
+mod non_normal_entries;
 mod status;
 use crate::dirstate::{
     dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,



To: Alphare, #hg-reviewers
Cc: kevincox, mercurial-devel


More information about the Mercurial-devel mailing list