Patchwork D5581: rust-cpython: set conversion for MissingAncestors.bases()

login
register
mail settings
Submitter phabricator
Date Jan. 16, 2019, 12:44 p.m.
Message ID <41b86cfa347e10f287325e37a8139ea1@localhost.localdomain>
Download mbox | patch
Permalink /patch/37788/
State Not Applicable
Headers show

Comments

phabricator - Jan. 16, 2019, 12:44 p.m.
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG5257e6299d4c: rust-cpython: set conversion for MissingAncestors.bases() (authored by gracinet, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D5581?vs=13215&id=13252

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

AFFECTED FILES
  rust/hg-cpython/src/ancestors.rs
  tests/test-rust-ancestor.py

CHANGE DETAILS




To: gracinet, #hg-reviewers, kevincox
Cc: durin42, kevincox, mercurial-devel

Patch

diff --git a/tests/test-rust-ancestor.py b/tests/test-rust-ancestor.py
--- a/tests/test-rust-ancestor.py
+++ b/tests/test-rust-ancestor.py
@@ -112,7 +112,7 @@ 
         self.assertTrue(missanc.hasbases())
         self.assertEqual(missanc.missingancestors([3]), [2, 3])
         missanc.addbases({2})
-        self.assertEqual(set(missanc.bases()), {1, 2})
+        self.assertEqual(missanc.bases(), {1, 2})
         self.assertEqual(missanc.missingancestors([3]), [3])
 
     def testmissingancestorsremove(self):
diff --git a/rust/hg-cpython/src/ancestors.rs b/rust/hg-cpython/src/ancestors.rs
--- a/rust/hg-cpython/src/ancestors.rs
+++ b/rust/hg-cpython/src/ancestors.rs
@@ -11,9 +11,9 @@ 
 //!
 //! # Classes visible from Python:
 //! - [`LazyAncestors`] is the Rust implementation of
-//!   `mercurial.ancestor.lazyancestors`.
-//!   The only difference is that it is instantiated with a C `parsers.index`
-//!   instance instead of a parents function.
+//!   `mercurial.ancestor.lazyancestors`. The only difference is that it is
+//!   instantiated with a C `parsers.index` instance instead of a parents
+//!   function.
 //!
 //! - [`MissingAncestors`] is the Rust implementation of
 //!   `mercurial.ancestor.incrementalmissingancestors`.
@@ -27,18 +27,18 @@ 
 //!      is accepted.
 //!
 //! - [`AncestorsIterator`] is the Rust counterpart of the
-//!   `ancestor._lazyancestorsiter` Python generator.
-//!   From Python, instances of this should be mainly obtained by calling
-//!   `iter()` on a [`LazyAncestors`] instance.
+//!   `ancestor._lazyancestorsiter` Python generator. From Python, instances of
+//!   this should be mainly obtained by calling `iter()` on a [`LazyAncestors`]
+//!   instance.
 //!
 //! [`LazyAncestors`]: struct.LazyAncestors.html
 //! [`MissingAncestors`]: struct.MissingAncestors.html
 //! [`AncestorsIterator`]: struct.AncestorsIterator.html
 use crate::conversion::rev_pyiter_collect;
 use cindex::Index;
 use cpython::{
-    ObjectProtocol, PyClone, PyDict, PyList, PyModule, PyObject,
-    PyResult, PyTuple, Python, PythonObject, ToPyObject,
+    ObjectProtocol, PyClone, PyDict, PyList, PyModule, PyObject, PyResult,
+    PyTuple, Python, PythonObject, ToPyObject,
 };
 use exceptions::GraphError;
 use hg::Revision;
@@ -90,6 +90,24 @@ 
     }
 }
 
+/// Copy and convert an `HashSet<Revision>` in a Python set
+///
+/// This will probably turn useless once `PySet` support lands in
+/// `rust-cpython`.
+///
+/// This builds a Python tuple, then calls Python's "set()" on it
+fn py_set(py: Python, set: &HashSet<Revision>) -> PyResult<PyObject> {
+    let as_vec: Vec<PyObject> = set
+        .iter()
+        .map(|rev| rev.to_py_object(py).into_object())
+        .collect();
+    let as_pytuple = PyTuple::new(py, as_vec.as_slice());
+
+    let locals = PyDict::new(py);
+    locals.set_item(py, "obj", as_pytuple.to_py_object(py))?;
+    py.eval("set(obj)", None, Some(&locals))
+}
+
 py_class!(pub class LazyAncestors |py| {
     data inner: RefCell<Box<CoreLazy<Index>>>;
 
@@ -144,16 +162,8 @@ 
         Ok(py.None())
     }
 
-    def bases(&self) -> PyResult<PyTuple> {
-        let inner = self.inner(py).borrow();
-        let bases_set = inner.get_bases();
-        // convert as Python tuple TODO how to return a proper Python set?
-        let mut bases_vec: Vec<PyObject> = Vec::with_capacity(
-            bases_set.len());
-        for rev in bases_set {
-            bases_vec.push(rev.to_py_object(py).into_object());
-        }
-        Ok(PyTuple::new(py, bases_vec.as_slice()))
+    def bases(&self) -> PyResult<PyObject> {
+        py_set(py, self.inner(py).borrow().get_bases())
     }
 
     def removeancestorsfrom(&self, revs: PyObject) -> PyResult<PyObject> {