D8152: revlog: using two new functions in C capsule from Rust code
Alphare (Raphaël Gomès)
phabricator at mercurial-scm.org
Wed Feb 26 17:36:38 UTC 2020
Alphare created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.
REVISION SUMMARY
We expose `index_length` and `index_node` in the C capsule, so that
the Rust representation of the C index can implement the `RevlogIndex`
trait.
Because our `Node` is actually a one-field struct, we have
to decorate it for direct FFI exchange with the C `char*`
It would be a good thing to get a length from the C layer, but doing
so right now would probably interfere with the upcoming changes that
will happen there for the hash length.
REPOSITORY
rHG Mercurial
BRANCH
default
REVISION DETAIL
https://phab.mercurial-scm.org/D8152
AFFECTED FILES
mercurial/cext/revlog.c
rust/hg-core/src/revlog/node.rs
rust/hg-cpython/src/cindex.rs
CHANGE DETAILS
diff --git a/rust/hg-cpython/src/cindex.rs b/rust/hg-cpython/src/cindex.rs
--- a/rust/hg-cpython/src/cindex.rs
+++ b/rust/hg-cpython/src/cindex.rs
@@ -11,14 +11,21 @@
//! but this will take some time to get there.
use cpython::{exc::ImportError, PyClone, PyErr, PyObject, PyResult, Python};
+use hg::revlog::{Node, RevlogIndex};
use hg::{Graph, GraphError, Revision, WORKING_DIRECTORY_REVISION};
use libc::c_int;
-const REVLOG_CABI_VERSION: c_int = 1;
+const REVLOG_CABI_VERSION: c_int = 2;
#[repr(C)]
pub struct Revlog_CAPI {
abi_version: c_int,
+ index_length:
+ unsafe extern "C" fn(index: *mut revlog_capi::RawPyObject) -> c_int,
+ index_node: unsafe extern "C" fn(
+ index: *mut revlog_capi::RawPyObject,
+ rev: c_int,
+ ) -> *const Node,
index_parents: unsafe extern "C" fn(
index: *mut revlog_capi::RawPyObject,
rev: c_int,
@@ -131,3 +138,30 @@
}
}
}
+
+impl RevlogIndex for Index {
+ /// Note C return type is Py_ssize_t (hence signed), but we shall
+ /// force it to unsigned, because it's a length
+ fn len(&self) -> usize {
+ unsafe { (self.capi.index_length)(self.index.as_ptr()) as usize }
+ }
+
+ fn node<'a>(&'a self, rev: Revision) -> Option<&'a Node> {
+ let raw = unsafe {
+ (self.capi.index_node)(self.index.as_ptr(), rev as c_int)
+ };
+ if raw.is_null() {
+ None
+ } else {
+ // TODO it would be much better for the C layer to give us
+ // a length, since the hash length will change in the near
+ // future, but that's probably out of scope for the nodemap
+ // patch series.
+ //
+ // The root of that unsafety relies in the signature of
+ // `capi.index_node()` itself: returning a `Node` pointer
+ // whereas it's a `char *` in the C counterpart.
+ Some(unsafe { &*raw })
+ }
+ }
+}
diff --git a/rust/hg-core/src/revlog/node.rs b/rust/hg-core/src/revlog/node.rs
--- a/rust/hg-core/src/revlog/node.rs
+++ b/rust/hg-core/src/revlog/node.rs
@@ -44,6 +44,7 @@
/// [`nybbles_len`]: #method.nybbles_len
/// [`ExactLengthRequired`]: struct.NodeError#variant.ExactLengthRequired
#[derive(Clone, Debug, PartialEq)]
+#[repr(transparent)]
pub struct Node {
data: NodeData,
}
diff --git a/mercurial/cext/revlog.c b/mercurial/cext/revlog.c
--- a/mercurial/cext/revlog.c
+++ b/mercurial/cext/revlog.c
@@ -39,6 +39,8 @@
typedef struct {
int abi_version;
+ Py_ssize_t (*index_length)(const indexObject *);
+ const char *(*index_node)(indexObject *, Py_ssize_t);
int (*index_parents)(PyObject *, int, int *);
} Revlog_CAPI;
@@ -3040,7 +3042,9 @@
static Revlog_CAPI CAPI = {
/* increment the abi_version field upon each change in the Revlog_CAPI
struct or in the ABI of the listed functions */
- 1,
+ 2,
+ index_length,
+ index_node,
HgRevlogIndex_GetParents,
};
To: Alphare, #hg-reviewers
Cc: mercurial-devel
More information about the Mercurial-devel
mailing list