Mercurial > hg
changeset 44502:166349510398
revlog: using two new functions in C capsule from Rust code
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.
Differential Revision: https://phab.mercurial-scm.org/D8152
author | Georges Racinet <georges.racinet@octobus.net> |
---|---|
date | Mon, 13 Jan 2020 19:31:33 +0100 |
parents | 87b327de772c |
children | 887d0f921b34 |
files | mercurial/cext/revlog.c rust/hg-core/src/revlog/node.rs rust/hg-cpython/src/cindex.rs |
diffstat | 3 files changed, 41 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/cext/revlog.c Tue Feb 18 19:11:14 2020 +0100 +++ b/mercurial/cext/revlog.c Mon Jan 13 19:31:33 2020 +0100 @@ -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; @@ -2877,7 +2879,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, };
--- a/rust/hg-core/src/revlog/node.rs Tue Feb 18 19:11:14 2020 +0100 +++ b/rust/hg-core/src/revlog/node.rs Mon Jan 13 19:31:33 2020 +0100 @@ -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, }
--- a/rust/hg-cpython/src/cindex.rs Tue Feb 18 19:11:14 2020 +0100 +++ b/rust/hg-cpython/src/cindex.rs Mon Jan 13 19:31:33 2020 +0100 @@ -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 }) + } + } +}