D8157: rust-nodemap: use proper Index API instead of using the C API

2020-03-11 Thread Raphaël Gomès
Closed by commit rHG857cc79247ac: rust-nodemap: use proper Index API instead of 
using the C API (authored by Alphare).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8157?vs=20656=20695

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8157/new/

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

AFFECTED FILES
  rust/hg-cpython/src/revlog.rs

CHANGE DETAILS

diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs
--- a/rust/hg-cpython/src/revlog.rs
+++ b/rust/hg-cpython/src/revlog.rs
@@ -5,12 +5,20 @@
 // This software may be used and distributed according to the terms of the
 // GNU General Public License version 2 or any later version.
 
-use crate::cindex;
+use crate::{
+cindex,
+utils::{node_from_py_bytes, node_from_py_object},
+};
 use cpython::{
-exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule,
-PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject,
+exc::{IndexError, ValueError},
+ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject,
+PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
 };
-use hg::{nodemap::NodeMapError, NodeError, Revision};
+use hg::{
+nodemap::{NodeMapError, NodeTree},
+revlog::{nodemap::NodeMap, RevlogIndex},
+NodeError, Revision,
+};
 use std::cell::RefCell;
 
 /// Return a Struct implementing the Graph trait
@@ -26,6 +34,7 @@
 
 py_class!(pub class MixedIndex |py| {
 data cindex: RefCell;
+data nt: RefCell>;
 
 def __new__(_cls, cindex: PyObject) -> PyResult {
 Self::new(py, cindex)
@@ -42,8 +51,99 @@
 Ok(self.cindex(py).borrow().inner().clone_ref(py))
 }
 
+// Index API involving nodemap, as defined in mercurial/pure/parsers.py
 
+/// Return Revision if found, raises a bare `error.RevlogError`
+/// in case of ambiguity, same as C version does
+def get_rev(, node: PyBytes) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+let node = node_from_py_bytes(py, )?;
+nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e))
+}
+
+/// same as `get_rev()` but raises a bare `error.RevlogError` if node
+/// is not found.
+///
+/// No need to repeat `node` in the exception, `mercurial/revlog.py`
+/// will catch and rewrap with it
+def rev(, node: PyBytes) -> PyResult {
+self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
+}
+
+/// return True if the node exist in the index
+def has_node(, node: PyBytes) -> PyResult {
+self.get_rev(py, node).map(|opt| opt.is_some())
+}
+
+/// find length of shortest hex nodeid of a binary ID
+def shortest(, node: PyBytes) -> PyResult {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?)
+{
+Ok(Some(l)) => Ok(l),
+Ok(None) => Err(revlog_error(py)),
+Err(e) => Err(nodemap_error(py, e)),
+}
+}
+
+def partialmatch(, node: PyObject) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+
+let node_as_string = if cfg!(feature = "python3-sys") {
+node.cast_as::(py)?.to_string(py)?.to_string()
+}
+else {
+let node = node.extract::(py)?;
+String::from_utf8_lossy(node.data(py)).to_string()
+};
+
+nt.find_hex(idx, _as_string)
+// TODO make an inner API returning the node directly
+.map(|opt| opt.map(
+|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes(
+.map_err(|e| nodemap_error(py, e))
+
+}
+
+/// append an index entry
+def append(, tup: PyTuple) -> PyResult {
+if tup.len(py) < 8 {
+// this is better than the panic promised by tup.get_item()
+return Err(
+PyErr::new::(py, "tuple index out of range"))
+}
+let node_bytes = tup.get_item(py, 7).extract(py)?;
+let node = node_from_py_object(py, _bytes)?;
+
+let mut idx = self.cindex(py).borrow_mut();
+let rev = idx.len() as Revision;
+
+idx.append(py, tup)?;
+self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
+.insert(&*idx, , rev)
+.map_err(|e| nodemap_error(py, e))?;
+Ok(py.None())
+}
+
+def __delitem__(, key: PyObject) -> PyResult<()> {
+// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
+

D8157: rust-nodemap: use proper Index API instead of using the C API

2020-03-10 Thread Raphaël Gomès
Alphare updated this revision to Diff 20656.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8157?vs=20376=20656

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8157/new/

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

AFFECTED FILES
  rust/hg-cpython/src/revlog.rs

CHANGE DETAILS

diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs
--- a/rust/hg-cpython/src/revlog.rs
+++ b/rust/hg-cpython/src/revlog.rs
@@ -5,12 +5,20 @@
 // This software may be used and distributed according to the terms of the
 // GNU General Public License version 2 or any later version.
 
-use crate::cindex;
+use crate::{
+cindex,
+utils::{node_from_py_bytes, node_from_py_object},
+};
 use cpython::{
-exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule,
-PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject,
+exc::{IndexError, ValueError},
+ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject,
+PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
 };
-use hg::{nodemap::NodeMapError, NodeError, Revision};
+use hg::{
+nodemap::{NodeMapError, NodeTree},
+revlog::{nodemap::NodeMap, RevlogIndex},
+NodeError, Revision,
+};
 use std::cell::RefCell;
 
 /// Return a Struct implementing the Graph trait
@@ -26,6 +34,7 @@
 
 py_class!(pub class MixedIndex |py| {
 data cindex: RefCell;
+data nt: RefCell>;
 
 def __new__(_cls, cindex: PyObject) -> PyResult {
 Self::new(py, cindex)
@@ -42,8 +51,99 @@
 Ok(self.cindex(py).borrow().inner().clone_ref(py))
 }
 
+// Index API involving nodemap, as defined in mercurial/pure/parsers.py
 
+/// Return Revision if found, raises a bare `error.RevlogError`
+/// in case of ambiguity, same as C version does
+def get_rev(, node: PyBytes) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+let node = node_from_py_bytes(py, )?;
+nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e))
+}
+
+/// same as `get_rev()` but raises a bare `error.RevlogError` if node
+/// is not found.
+///
+/// No need to repeat `node` in the exception, `mercurial/revlog.py`
+/// will catch and rewrap with it
+def rev(, node: PyBytes) -> PyResult {
+self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
+}
+
+/// return True if the node exist in the index
+def has_node(, node: PyBytes) -> PyResult {
+self.get_rev(py, node).map(|opt| opt.is_some())
+}
+
+/// find length of shortest hex nodeid of a binary ID
+def shortest(, node: PyBytes) -> PyResult {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?)
+{
+Ok(Some(l)) => Ok(l),
+Ok(None) => Err(revlog_error(py)),
+Err(e) => Err(nodemap_error(py, e)),
+}
+}
+
+def partialmatch(, node: PyObject) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+
+let node_as_string = if cfg!(feature = "python3-sys") {
+node.cast_as::(py)?.to_string(py)?.to_string()
+}
+else {
+let node = node.extract::(py)?;
+String::from_utf8_lossy(node.data(py)).to_string()
+};
+
+nt.find_hex(idx, _as_string)
+// TODO make an inner API returning the node directly
+.map(|opt| opt.map(
+|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes(
+.map_err(|e| nodemap_error(py, e))
+
+}
+
+/// append an index entry
+def append(, tup: PyTuple) -> PyResult {
+if tup.len(py) < 8 {
+// this is better than the panic promised by tup.get_item()
+return Err(
+PyErr::new::(py, "tuple index out of range"))
+}
+let node_bytes = tup.get_item(py, 7).extract(py)?;
+let node = node_from_py_object(py, _bytes)?;
+
+let mut idx = self.cindex(py).borrow_mut();
+let rev = idx.len() as Revision;
+
+idx.append(py, tup)?;
+self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
+.insert(&*idx, , rev)
+.map_err(|e| nodemap_error(py, e))?;
+Ok(py.None())
+}
+
+def __delitem__(, key: PyObject) -> PyResult<()> {
+// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
+self.cindex(py).borrow().inner().del_item(py, key)?;
+let mut opt = self.get_nodetree(py)?.borrow_mut();
+let mut nt = opt.as_mut().unwrap();
+nt.invalidate_all();
+self.fill_nodemap(py,  nt)?;
+Ok(())
+}
+

D8157: rust-nodemap: use proper Index API instead of using the C API

2020-02-28 Thread marmoute (Pierre-Yves David)
marmoute updated this revision to Diff 20376.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8157?vs=20332=20376

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8157/new/

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

AFFECTED FILES
  rust/hg-cpython/src/revlog.rs

CHANGE DETAILS

diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs
--- a/rust/hg-cpython/src/revlog.rs
+++ b/rust/hg-cpython/src/revlog.rs
@@ -5,12 +5,20 @@
 // This software may be used and distributed according to the terms of the
 // GNU General Public License version 2 or any later version.
 
-use crate::cindex;
+use crate::{
+cindex,
+utils::{node_from_py_bytes, node_from_py_object},
+};
 use cpython::{
-exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule,
-PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject,
+exc::{IndexError, ValueError},
+ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject,
+PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
 };
-use hg::{nodemap::NodeMapError, NodeError, Revision};
+use hg::{
+nodemap::{NodeMapError, NodeTree},
+revlog::{nodemap::NodeMap, RevlogIndex},
+NodeError, Revision,
+};
 use std::cell::RefCell;
 
 /// Return a Struct implementing the Graph trait
@@ -26,6 +34,7 @@
 
 py_class!(pub class MixedIndex |py| {
 data cindex: RefCell;
+data nt: RefCell>;
 
 def __new__(_cls, cindex: PyObject) -> PyResult {
 Self::new(py, cindex)
@@ -42,8 +51,99 @@
 Ok(self.cindex(py).borrow().inner().clone_ref(py))
 }
 
+// Index API involving nodemap, as defined in mercurial/pure/parsers.py
 
+/// Return Revision if found, raises a bare `error.RevlogError`
+/// in case of ambiguity, same as C version does
+def get_rev(, node: PyBytes) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+let node = node_from_py_bytes(py, )?;
+nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e))
+}
+
+/// same as `get_rev()` but raises a bare `error.RevlogError` if node
+/// is not found.
+///
+/// No need to repeat `node` in the exception, `mercurial/revlog.py`
+/// will catch and rewrap with it
+def rev(, node: PyBytes) -> PyResult {
+self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
+}
+
+/// return True if the node exist in the index
+def has_node(, node: PyBytes) -> PyResult {
+self.get_rev(py, node).map(|opt| opt.is_some())
+}
+
+/// find length of shortest hex nodeid of a binary ID
+def shortest(, node: PyBytes) -> PyResult {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?)
+{
+Ok(Some(l)) => Ok(l),
+Ok(None) => Err(revlog_error(py)),
+Err(e) => Err(nodemap_error(py, e)),
+}
+}
+
+def partialmatch(, node: PyObject) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+
+let node_as_string = if cfg!(feature = "python3-sys") {
+node.cast_as::(py)?.to_string(py)?.to_string()
+}
+else {
+let node = node.extract::(py)?;
+String::from_utf8_lossy(node.data(py)).to_string()
+};
+
+nt.find_hex(idx, _as_string)
+// TODO make an inner API returning the node directly
+.map(|opt| opt.map(
+|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes(
+.map_err(|e| nodemap_error(py, e))
+
+}
+
+/// append an index entry
+def append(, tup: PyTuple) -> PyResult {
+if tup.len(py) < 8 {
+// this is better than the panic promised by tup.get_item()
+return Err(
+PyErr::new::(py, "tuple index out of range"))
+}
+let node_bytes = tup.get_item(py, 7).extract(py)?;
+let node = node_from_py_object(py, _bytes)?;
+
+let mut idx = self.cindex(py).borrow_mut();
+let rev = idx.len() as Revision;
+
+idx.append(py, tup)?;
+self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
+.insert(&*idx, , rev)
+.map_err(|e| nodemap_error(py, e))?;
+Ok(py.None())
+}
+
+def __delitem__(, key: PyObject) -> PyResult<()> {
+// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
+self.cindex(py).borrow().inner().del_item(py, key)?;
+let mut opt = self.get_nodetree(py)?.borrow_mut();
+let mut nt = opt.as_mut().unwrap();
+nt.invalidate_all();
+self.fill_nodemap(py,  nt)?;
+Ok(())
+}
+

D8157: rust-nodemap: use proper Index API instead of using the C API

2020-02-26 Thread Raphaël Gomès
Alphare created this revision.
Herald added subscribers: mercurial-devel, mjpieters.
Herald added a reviewer: hg-reviewers.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  rust/hg-cpython/src/revlog.rs

CHANGE DETAILS

diff --git a/rust/hg-cpython/src/revlog.rs b/rust/hg-cpython/src/revlog.rs
--- a/rust/hg-cpython/src/revlog.rs
+++ b/rust/hg-cpython/src/revlog.rs
@@ -5,12 +5,20 @@
 // This software may be used and distributed according to the terms of the
 // GNU General Public License version 2 or any later version.
 
-use crate::cindex;
+use crate::{
+cindex,
+utils::{node_from_py_bytes, node_from_py_object},
+};
 use cpython::{
-exc::ValueError, ObjectProtocol, PyClone, PyDict, PyErr, PyModule,
-PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject,
+exc::{IndexError, ValueError},
+ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyModule, PyObject,
+PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
 };
-use hg::{nodemap::NodeMapError, NodeError, Revision};
+use hg::{
+nodemap::{NodeMapError, NodeTree},
+revlog::{nodemap::NodeMap, RevlogIndex},
+NodeError, Revision,
+};
 use std::cell::RefCell;
 
 /// Return a Struct implementing the Graph trait
@@ -26,6 +34,7 @@
 
 py_class!(pub class MixedIndex |py| {
 data cindex: RefCell;
+data nt: RefCell>;
 
 def __new__(_cls, cindex: PyObject) -> PyResult {
 Self::new(py, cindex)
@@ -42,8 +51,90 @@
 Ok(self.cindex(py).borrow().inner().clone_ref(py))
 }
 
+// Index API involving nodemap, as defined in mercurial/pure/parsers.py
 
+/// Return Revision if found, raises a bare `error.RevlogError`
+/// in case of ambiguity, same as C version does
+def get_rev(, node: PyBytes) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+let node = node_from_py_bytes(py, )?;
+nt.find_bin(idx, ().into()).map_err(|e| nodemap_error(py, e))
+}
+
+/// same as `get_rev()` but raises a bare `error.RevlogError` if node
+/// is not found.
+///
+/// No need to repeat `node` in the exception, `mercurial/revlog.py`
+/// will catch and rewrap with it
+def rev(, node: PyBytes) -> PyResult {
+self.get_rev(py, node)?.ok_or_else(|| revlog_error(py))
+}
+
+/// return True if the node exist in the index
+def has_node(, node: PyBytes) -> PyResult {
+self.get_rev(py, node).map(|opt| opt.is_some())
+}
+
+/// find length of shortest hex nodeid of a binary ID
+def shortest(, node: PyBytes) -> PyResult {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+match nt.unique_prefix_len_node(idx, _from_py_bytes(py, )?)
+{
+Ok(Some(l)) => Ok(l),
+Ok(None) => Err(revlog_error(py)),
+Err(e) => Err(nodemap_error(py, e)),
+}
+}
+
+// TODO in py3, I suppose we get PyBytes, actually
+def partialmatch(, node: PyString) -> PyResult> {
+let opt = self.get_nodetree(py)?.borrow();
+let nt = opt.as_ref().unwrap();
+let idx = &*self.cindex(py).borrow();
+nt.find_hex(idx, _string(py)?)
+// TODO make an inner API returning the node directly
+.map(|opt| opt.map(
+|rev| PyBytes::new(py, idx.node(rev).unwrap().as_bytes(
+.map_err(|e| nodemap_error(py, e))
+}
+
+/// append an index entry
+def append(, tup: PyTuple) -> PyResult {
+if tup.len(py) < 8 {
+// this is better than the panic promised by tup.get_item()
+return Err(
+PyErr::new::(py, "tuple index out of range"))
+}
+let node_bytes = tup.get_item(py, 7).extract(py)?;
+let node = node_from_py_object(py, _bytes)?;
+
+let mut idx = self.cindex(py).borrow_mut();
+let rev = idx.len() as Revision;
+
+idx.append(py, tup)?;
+self.get_nodetree(py)?.borrow_mut().as_mut().unwrap()
+.insert(&*idx, , rev)
+.map_err(|e| nodemap_error(py, e))?;
+Ok(py.None())
+}
+
+def __delitem__(, key: PyObject) -> PyResult<()> {
+// __delitem__ is both for `del idx[r]` and `del idx[r1:r2]`
+self.cindex(py).borrow().inner().del_item(py, key)?;
+let mut opt = self.get_nodetree(py)?.borrow_mut();
+let mut nt = opt.as_mut().unwrap();
+nt.invalidate_all();
+self.fill_nodemap(py,  nt)?;
+Ok(())
+}
+
+//
 // Reforwarded C index API
+//
 
 // index_methods (tp_methods). Same ordering as in revlog.c
 
@@ -67,21 +158,6 @@
 self.call_cindex(py, "get", args, kw)
 }
 
-/// return `rev` associated with a node or None
-def get_rev(, *args, **kw) -> PyResult {
-