Re: [PATCH 2 of 5 RFC] rust: iterator bindings to C code

2019-01-16 Thread Augie Fackler


> On Jan 16, 2019, at 11:13, Georges Racinet  
> wrote:
> 
> Hi Augie,
> 
> On 10/1/18 5:02 PM, Augie Fackler wrote:
>> On Fri, Sep 28, 2018 at 03:31:09PM +0200, Georges Racinet wrote:
>>> # HG changeset patch
>>> # User Georges Racinet 
>>> # Date 1538059896 -7200
>>> #  Thu Sep 27 16:51:36 2018 +0200
>>> # Node ID de88c09512565ed1c12e2ff9159e06ed8d762d15
>>> # Parent  d8c9571755a64e1fc3429587dfd3949b9862eceb
>>> # EXP-Topic rustancestors-rfc
>>> rust: iterator bindings to C code
>>> 
>>> In this changeset, still made of Rust code only,
>>> we expose the Rust iterator for instantiation and
>>> consumption from C code.
>>> 
>>> The idea is that both the index and index_get_parents()
>>> will be passed from the C extension, hence avoiding a hard
>>> link dependency to parsers.so, so that the crate can
>>> still be built and tested independently.
>>> 
>>> On the other hand, parsers.so will use the symbols
>>> defined in this changeset.
>>> 
>>> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.lock
>>> --- a/mercurial/rust/Cargo.lock Thu Sep 27 17:03:16 2018 +0200
>>> +++ b/mercurial/rust/Cargo.lock Thu Sep 27 16:51:36 2018 +0200
>>> @@ -1,4 +1,14 @@
>>> [[package]]
>>> name = "hgancestors"
>>> version = "0.1.0"
>>> +dependencies = [
>>> + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
>>> +]
>>> 
>>> +[[package]]
>>> +name = "libc"
>>> +version = "0.2.43"
>>> +source = "registry+https://github.com/rust-lang/crates.io-index;
>>> +
>>> +[metadata]
>>> +"checksum libc 0.2.43 
>>> (registry+https://github.com/rust-lang/crates.io-index)" = 
>>> "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
>>> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.toml
>>> --- a/mercurial/rust/Cargo.toml Thu Sep 27 17:03:16 2018 +0200
>>> +++ b/mercurial/rust/Cargo.toml Thu Sep 27 16:51:36 2018 +0200
>>> @@ -2,3 +2,9 @@
>>> name = "hgancestors"
>>> version = "0.1.0"
>>> authors = ["Georges Racinet "]
>>> +
>>> +[dependencies]
>>> +libc = "*"
>>> +
>>> +[lib]
>>> +crate-type = ["dylib"]
>>> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/src/cpython.rs
>>> --- /dev/null   Thu Jan 01 00:00:00 1970 +
>>> +++ b/mercurial/rust/src/cpython.rs Thu Sep 27 16:51:36 2018 +0200
>>> @@ -0,0 +1,170 @@
>>> +// Copyright 2018 Georges Racinet 
>>> +//
>>> +// This software may be used and distributed according to the terms of the
>>> +// GNU General Public License version 2 or any later version.
>>> +
>>> +//! Bindings for CPython extension code
>> This looks like you're using cffi and not cpython extension logic? I
>> don't see anything python-specific in here, so maybe this is misnamed?
> This patch is outdated, and the corresponding code has been moved during
> the October sprint in its own crate, rust/hg-direct-ffi, before Yuya
> queued it.

Ugh, I did something dumb on my laptop and a bunch of zombie messages got sent 
today. Sorry!

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 5 RFC] rust: iterator bindings to C code

2019-01-16 Thread Georges Racinet
Hi Augie,

On 10/1/18 5:02 PM, Augie Fackler wrote:
> On Fri, Sep 28, 2018 at 03:31:09PM +0200, Georges Racinet wrote:
>> # HG changeset patch
>> # User Georges Racinet 
>> # Date 1538059896 -7200
>> #  Thu Sep 27 16:51:36 2018 +0200
>> # Node ID de88c09512565ed1c12e2ff9159e06ed8d762d15
>> # Parent  d8c9571755a64e1fc3429587dfd3949b9862eceb
>> # EXP-Topic rustancestors-rfc
>> rust: iterator bindings to C code
>>
>> In this changeset, still made of Rust code only,
>> we expose the Rust iterator for instantiation and
>> consumption from C code.
>>
>> The idea is that both the index and index_get_parents()
>> will be passed from the C extension, hence avoiding a hard
>> link dependency to parsers.so, so that the crate can
>> still be built and tested independently.
>>
>> On the other hand, parsers.so will use the symbols
>> defined in this changeset.
>>
>> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.lock
>> --- a/mercurial/rust/Cargo.lock  Thu Sep 27 17:03:16 2018 +0200
>> +++ b/mercurial/rust/Cargo.lock  Thu Sep 27 16:51:36 2018 +0200
>> @@ -1,4 +1,14 @@
>>  [[package]]
>>  name = "hgancestors"
>>  version = "0.1.0"
>> +dependencies = [
>> + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
>> +]
>>
>> +[[package]]
>> +name = "libc"
>> +version = "0.2.43"
>> +source = "registry+https://github.com/rust-lang/crates.io-index;
>> +
>> +[metadata]
>> +"checksum libc 0.2.43 
>> (registry+https://github.com/rust-lang/crates.io-index)" = 
>> "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
>> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.toml
>> --- a/mercurial/rust/Cargo.toml  Thu Sep 27 17:03:16 2018 +0200
>> +++ b/mercurial/rust/Cargo.toml  Thu Sep 27 16:51:36 2018 +0200
>> @@ -2,3 +2,9 @@
>>  name = "hgancestors"
>>  version = "0.1.0"
>>  authors = ["Georges Racinet "]
>> +
>> +[dependencies]
>> +libc = "*"
>> +
>> +[lib]
>> +crate-type = ["dylib"]
>> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/src/cpython.rs
>> --- /dev/nullThu Jan 01 00:00:00 1970 +
>> +++ b/mercurial/rust/src/cpython.rs  Thu Sep 27 16:51:36 2018 +0200
>> @@ -0,0 +1,170 @@
>> +// Copyright 2018 Georges Racinet 
>> +//
>> +// This software may be used and distributed according to the terms of the
>> +// GNU General Public License version 2 or any later version.
>> +
>> +//! Bindings for CPython extension code
> This looks like you're using cffi and not cpython extension logic? I
> don't see anything python-specific in here, so maybe this is misnamed?
This patch is outdated, and the corresponding code has been moved during
the October sprint in its own crate, rust/hg-direct-ffi, before Yuya
queued it.
>
> If I've misread this, why this route rather than using the cpython
> crate, so that the `unsafe` code is consolidated into one package?

This is indeed the way forward that's been adopted since then (see
rust/hg-cpython). I believe there was a rationale for this choice in one
of the changesets of the series. The TL;DR would be that it wasn't clear
at that time how Rust code could call index_get_parents() from parsers.c
[1] and that it could be done without choosing between the three options
presented in the Oxidation wiki page (namely rust-cpython, pyo3 and
cffi), something I wasn't at ease with before meeting other developers IRL.

Now it is expected that hg-direct-ffi will die in some not-too-far future.

Hope this helps,

[1] now it is, this is what PyCapsule is meant for, but I discovered it
later, also during the October sprint. As a side note, I have a
currently a PR about it in rust-cpython which will reduce the amount of
unsafe code in hg-cpython if I can make it land.

-- 
Georges Racinet
https://octobus.net
GPG: BF5456F4DC625443849B6E58EE20CA44EF691D39, sur serveurs publics




signature.asc
Description: OpenPGP digital signature
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 5 RFC] rust: iterator bindings to C code

2019-01-16 Thread Augie Fackler
On Fri, Sep 28, 2018 at 03:31:09PM +0200, Georges Racinet wrote:
> # HG changeset patch
> # User Georges Racinet 
> # Date 1538059896 -7200
> #  Thu Sep 27 16:51:36 2018 +0200
> # Node ID de88c09512565ed1c12e2ff9159e06ed8d762d15
> # Parent  d8c9571755a64e1fc3429587dfd3949b9862eceb
> # EXP-Topic rustancestors-rfc
> rust: iterator bindings to C code
>
> In this changeset, still made of Rust code only,
> we expose the Rust iterator for instantiation and
> consumption from C code.
>
> The idea is that both the index and index_get_parents()
> will be passed from the C extension, hence avoiding a hard
> link dependency to parsers.so, so that the crate can
> still be built and tested independently.
>
> On the other hand, parsers.so will use the symbols
> defined in this changeset.
>
> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.lock
> --- a/mercurial/rust/Cargo.lock   Thu Sep 27 17:03:16 2018 +0200
> +++ b/mercurial/rust/Cargo.lock   Thu Sep 27 16:51:36 2018 +0200
> @@ -1,4 +1,14 @@
>  [[package]]
>  name = "hgancestors"
>  version = "0.1.0"
> +dependencies = [
> + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
> +]
>
> +[[package]]
> +name = "libc"
> +version = "0.2.43"
> +source = "registry+https://github.com/rust-lang/crates.io-index;
> +
> +[metadata]
> +"checksum libc 0.2.43 
> (registry+https://github.com/rust-lang/crates.io-index)" = 
> "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.toml
> --- a/mercurial/rust/Cargo.toml   Thu Sep 27 17:03:16 2018 +0200
> +++ b/mercurial/rust/Cargo.toml   Thu Sep 27 16:51:36 2018 +0200
> @@ -2,3 +2,9 @@
>  name = "hgancestors"
>  version = "0.1.0"
>  authors = ["Georges Racinet "]
> +
> +[dependencies]
> +libc = "*"
> +
> +[lib]
> +crate-type = ["dylib"]
> diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/src/cpython.rs
> --- /dev/null Thu Jan 01 00:00:00 1970 +
> +++ b/mercurial/rust/src/cpython.rs   Thu Sep 27 16:51:36 2018 +0200
> @@ -0,0 +1,170 @@
> +// Copyright 2018 Georges Racinet 
> +//
> +// This software may be used and distributed according to the terms of the
> +// GNU General Public License version 2 or any later version.
> +
> +//! Bindings for CPython extension code

This looks like you're using cffi and not cpython extension logic? I
don't see anything python-specific in here, so maybe this is misnamed?

If I've misread this, why this route rather than using the cpython
crate, so that the `unsafe` code is consolidated into one package?

> +//!
> +//! This exposes methods to build and use a `rustlazyancestors` iterator
> +//! from C code, using an index and its parents function that are passed
> +//! from the caller at instantiation.
> +
> +extern crate libc;
> +
> +use std::boxed::Box;
> +use self::libc::{c_void, c_int, ssize_t};
> +use super::ancestors::{Graph, AncestorsIterator};
> +
> +type IndexPtr = *mut c_void;
> +type IndexParentsFn = extern "C" fn(index: IndexPtr,
> +rev: ssize_t,
> +ps: *mut [c_int; 2],
> +max_rev: c_int)
> +-> c_int;
> +
> +/// A Graph backed up by objects and functions from revlog.c
> +///
> +/// This implementation of the Graph trait, relies on (pointers to)
> +/// - the C index object (`index` member)
> +/// - the `index_get_parents()` function (`parents` member)
> +pub struct Index {
> +index: IndexPtr,
> +parents: IndexParentsFn,
> +}
> +
> +impl Index {
> +pub fn new(index: IndexPtr, parents: IndexParentsFn) -> Self {
> +Index {
> +index: index,
> +parents: parents,
> +}
> +}
> +}
> +
> +impl Graph for Index {
> +/// wrap a call to the C extern parents function
> +fn parents(, rev: i32) -> (i32, i32) {
> +let mut res: [c_int; 2] = [0; 2];
> +// surprisingly the call below is not unsafe, whereas calling the
> +// same extern function directly (not through a pointer) would.
> +// Maybe that depends on rustc version, though.
> +let code = (self.parents)(
> +self.index,
> +rev as ssize_t,
> + res as *mut [c_int; 2],
> +rev,
> +);
> +if code != 0 {
> +// TODO panic! and FFI don't get well together
> +panic!("Corrupted index");
> +}
> +(res[0], res[1])
> +}
> +}
> +
> +/// Wrapping of AncestorsIterator constructor, for C callers.
> +///
> +/// Besides `initrevs`, `stoprev` and `inclusive`, that are converted
> +/// we receive the index and the parents function as pointers
> +#[no_mangle]
> +pub extern "C" fn rustlazyancestors_init(
> +index: IndexPtr,
> +parents: IndexParentsFn,
> +initrevslen: usize,
> +initrevs: *mut i64,
> +stoprev: i64,
> +inclusive: i64,
> +) -> *mut AncestorsIterator {
> +let v: Vec =
> +  

Re: [PATCH 2 of 5 RFC] rust: iterator bindings to C code

2018-09-30 Thread Georges Racinet
On 9/30/18 5:46 AM, Yuya Nishihara wrote:
> On Fri, 28 Sep 2018 15:31:09 +0200, Georges Racinet wrote:
>> # HG changeset patch
>> # User Georges Racinet 
>> # Date 1538059896 -7200
>> #  Thu Sep 27 16:51:36 2018 +0200
>> # Node ID de88c09512565ed1c12e2ff9159e06ed8d762d15
>> # Parent  d8c9571755a64e1fc3429587dfd3949b9862eceb
>> # EXP-Topic rustancestors-rfc
>> rust: iterator bindings to C code
>>
>> In this changeset, still made of Rust code only,
>> we expose the Rust iterator for instantiation and
>> consumption from C code.
>>
>> The idea is that both the index and index_get_parents()
>> will be passed from the C extension, hence avoiding a hard
>> link dependency to parsers.so, so that the crate can
>> still be built and tested independently.
> Just a note. That means parents() can't take hidden revisions into account.
> We might have to filter out hidden revisions from the initial set.
Yes, that's the plan.
>
> Another idea is to scan the revlog index in pure Rust. That's fairly easy
> since each revlog entry is fixed sized unless data is inlined. I'm sure
> there are several revlog parsers written by Mecurial folks to learn Rust.
> I have one. :)

I'd love to see it and agree that hooking onto such a parser could be
seen as a longer term perspective for what we're doing incrementally here.

On the other hand, I dismissed the idea to implement index_get_parents()
in Rust over the index C data structure as a bit too complicated, as it
seems to involve Python objects, and hence would require the help of
rust-cpython or a similar library.

>
>> +use std::boxed::Box;
> Nit: it's included in prelude.
Noted
>
>> +type IndexPtr = *mut c_void;
>> +type IndexParentsFn = extern "C" fn(index: IndexPtr,
>> +rev: ssize_t,
>> +ps: *mut [c_int; 2],
>> +max_rev: c_int)
>> +-> c_int;
> ...
>
>> +impl Graph for Index {
>> +/// wrap a call to the C extern parents function
>> +fn parents(, rev: i32) -> (i32, i32) {
>> +let mut res: [c_int; 2] = [0; 2];
>> +// surprisingly the call below is not unsafe, whereas calling the
>> +// same extern function directly (not through a pointer) would.
>> +// Maybe that depends on rustc version, though.
>> +let code = (self.parents)(
> Perhaps, the IndexParentsFn type has to be labeled as "unsafe fn".
Ah yes, you're right, it works. The fact is, with a function pointer,
the Rust compiler can't know whether it's from external code or just
meant for external usage, should have thought of that.
>
>> +/// Wrapping of AncestorsIterator constructor, for C callers.
>> +///
>> +/// Besides `initrevs`, `stoprev` and `inclusive`, that are converted
>> +/// we receive the index and the parents function as pointers
>> +#[no_mangle]
>> +pub extern "C" fn rustlazyancestors_init(
>> +index: IndexPtr,
>> +parents: IndexParentsFn,
>> +initrevslen: usize,
>> +initrevs: *mut i64,
>> +stoprev: i64,
>> +inclusive: i64,
>> +) -> *mut AncestorsIterator {
>> +let v: Vec =
>> +unsafe { Vec::from_raw_parts(initrevs, initrevslen, initrevslen) };
> It's probably wrong to construct a Vec from a memory not allocated in Rust.
> Rust uses specialized malloc() variants. IIRC, the default is jemalloc and
> Vec has some other optimizations.

Yes, you're right, it makes much more sense to abide by the rule that
memory allocated by one language should be freed by the same one.

Given that and your earlier comments, I'll probably submit a new version
where rustlazyancestors_init() makes an iterator over revision numbers
(ie, i32) out of the initrevs it receives and pass it to
AncestorsIterator::new(). The raw pointer (initrevs array) will then be
freed from the C caller.

Also need to replace all occurrences of i64 by c_long for platform
independence.

Thanks for the comments,

-- 
Georges Racinet
Anybox SAS, http://anybox.fr
Téléphone: +33 6 51 32 07 27
GPG: B59E 22AB B842 CAED 77F7 7A7F C34F A519 33AB 0A35, sur serveurs publics


___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 5 RFC] rust: iterator bindings to C code

2018-09-29 Thread Yuya Nishihara
On Fri, 28 Sep 2018 15:31:09 +0200, Georges Racinet wrote:
> # HG changeset patch
> # User Georges Racinet 
> # Date 1538059896 -7200
> #  Thu Sep 27 16:51:36 2018 +0200
> # Node ID de88c09512565ed1c12e2ff9159e06ed8d762d15
> # Parent  d8c9571755a64e1fc3429587dfd3949b9862eceb
> # EXP-Topic rustancestors-rfc
> rust: iterator bindings to C code
> 
> In this changeset, still made of Rust code only,
> we expose the Rust iterator for instantiation and
> consumption from C code.
> 
> The idea is that both the index and index_get_parents()
> will be passed from the C extension, hence avoiding a hard
> link dependency to parsers.so, so that the crate can
> still be built and tested independently.

Just a note. That means parents() can't take hidden revisions into account.
We might have to filter out hidden revisions from the initial set.

Another idea is to scan the revlog index in pure Rust. That's fairly easy
since each revlog entry is fixed sized unless data is inlined. I'm sure
there are several revlog parsers written by Mecurial folks to learn Rust.
I have one. :)

> +use std::boxed::Box;

Nit: it's included in prelude.

> +type IndexPtr = *mut c_void;
> +type IndexParentsFn = extern "C" fn(index: IndexPtr,
> +rev: ssize_t,
> +ps: *mut [c_int; 2],
> +max_rev: c_int)
> +-> c_int;

...

> +impl Graph for Index {
> +/// wrap a call to the C extern parents function
> +fn parents(, rev: i32) -> (i32, i32) {
> +let mut res: [c_int; 2] = [0; 2];
> +// surprisingly the call below is not unsafe, whereas calling the
> +// same extern function directly (not through a pointer) would.
> +// Maybe that depends on rustc version, though.
> +let code = (self.parents)(

Perhaps, the IndexParentsFn type has to be labeled as "unsafe fn".

> +/// Wrapping of AncestorsIterator constructor, for C callers.
> +///
> +/// Besides `initrevs`, `stoprev` and `inclusive`, that are converted
> +/// we receive the index and the parents function as pointers
> +#[no_mangle]
> +pub extern "C" fn rustlazyancestors_init(
> +index: IndexPtr,
> +parents: IndexParentsFn,
> +initrevslen: usize,
> +initrevs: *mut i64,
> +stoprev: i64,
> +inclusive: i64,
> +) -> *mut AncestorsIterator {
> +let v: Vec =
> +unsafe { Vec::from_raw_parts(initrevs, initrevslen, initrevslen) };

It's probably wrong to construct a Vec from a memory not allocated in Rust.
Rust uses specialized malloc() variants. IIRC, the default is jemalloc and
Vec has some other optimizations.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 5 RFC] rust: iterator bindings to C code

2018-09-28 Thread Georges Racinet
# HG changeset patch
# User Georges Racinet 
# Date 1538059896 -7200
#  Thu Sep 27 16:51:36 2018 +0200
# Node ID de88c09512565ed1c12e2ff9159e06ed8d762d15
# Parent  d8c9571755a64e1fc3429587dfd3949b9862eceb
# EXP-Topic rustancestors-rfc
rust: iterator bindings to C code

In this changeset, still made of Rust code only,
we expose the Rust iterator for instantiation and
consumption from C code.

The idea is that both the index and index_get_parents()
will be passed from the C extension, hence avoiding a hard
link dependency to parsers.so, so that the crate can
still be built and tested independently.

On the other hand, parsers.so will use the symbols
defined in this changeset.

diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.lock
--- a/mercurial/rust/Cargo.lock Thu Sep 27 17:03:16 2018 +0200
+++ b/mercurial/rust/Cargo.lock Thu Sep 27 16:51:36 2018 +0200
@@ -1,4 +1,14 @@
 [[package]]
 name = "hgancestors"
 version = "0.1.0"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
+[[package]]
+name = "libc"
+version = "0.2.43"
+source = "registry+https://github.com/rust-lang/crates.io-index;
+
+[metadata]
+"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" 
= "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/Cargo.toml
--- a/mercurial/rust/Cargo.toml Thu Sep 27 17:03:16 2018 +0200
+++ b/mercurial/rust/Cargo.toml Thu Sep 27 16:51:36 2018 +0200
@@ -2,3 +2,9 @@
 name = "hgancestors"
 version = "0.1.0"
 authors = ["Georges Racinet "]
+
+[dependencies]
+libc = "*"
+
+[lib]
+crate-type = ["dylib"]
diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/src/cpython.rs
--- /dev/null   Thu Jan 01 00:00:00 1970 +
+++ b/mercurial/rust/src/cpython.rs Thu Sep 27 16:51:36 2018 +0200
@@ -0,0 +1,170 @@
+// Copyright 2018 Georges Racinet 
+//
+// This software may be used and distributed according to the terms of the
+// GNU General Public License version 2 or any later version.
+
+//! Bindings for CPython extension code
+//!
+//! This exposes methods to build and use a `rustlazyancestors` iterator
+//! from C code, using an index and its parents function that are passed
+//! from the caller at instantiation.
+
+extern crate libc;
+
+use std::boxed::Box;
+use self::libc::{c_void, c_int, ssize_t};
+use super::ancestors::{Graph, AncestorsIterator};
+
+type IndexPtr = *mut c_void;
+type IndexParentsFn = extern "C" fn(index: IndexPtr,
+rev: ssize_t,
+ps: *mut [c_int; 2],
+max_rev: c_int)
+-> c_int;
+
+/// A Graph backed up by objects and functions from revlog.c
+///
+/// This implementation of the Graph trait, relies on (pointers to)
+/// - the C index object (`index` member)
+/// - the `index_get_parents()` function (`parents` member)
+pub struct Index {
+index: IndexPtr,
+parents: IndexParentsFn,
+}
+
+impl Index {
+pub fn new(index: IndexPtr, parents: IndexParentsFn) -> Self {
+Index {
+index: index,
+parents: parents,
+}
+}
+}
+
+impl Graph for Index {
+/// wrap a call to the C extern parents function
+fn parents(, rev: i32) -> (i32, i32) {
+let mut res: [c_int; 2] = [0; 2];
+// surprisingly the call below is not unsafe, whereas calling the
+// same extern function directly (not through a pointer) would.
+// Maybe that depends on rustc version, though.
+let code = (self.parents)(
+self.index,
+rev as ssize_t,
+ res as *mut [c_int; 2],
+rev,
+);
+if code != 0 {
+// TODO panic! and FFI don't get well together
+panic!("Corrupted index");
+}
+(res[0], res[1])
+}
+}
+
+/// Wrapping of AncestorsIterator constructor, for C callers.
+///
+/// Besides `initrevs`, `stoprev` and `inclusive`, that are converted
+/// we receive the index and the parents function as pointers
+#[no_mangle]
+pub extern "C" fn rustlazyancestors_init(
+index: IndexPtr,
+parents: IndexParentsFn,
+initrevslen: usize,
+initrevs: *mut i64,
+stoprev: i64,
+inclusive: i64,
+) -> *mut AncestorsIterator {
+let v: Vec =
+unsafe { Vec::from_raw_parts(initrevs, initrevslen, initrevslen) };
+let inclb = match inclusive {
+0 => false,
+1 => true,
+_ => panic!("Did not understand boolean FFI convention"),
+};
+
+Box::into_raw(Box::new(AncestorsIterator::new(
+Index::new(index, parents),
+,
+stoprev,
+inclb,
+)))
+}
+
+/// Deallocator to be called from C code
+#[no_mangle]
+pub extern "C" fn rustlazyancestors_drop(
+raw_iter: *mut AncestorsIterator,
+) {
+unsafe {
+Box::from_raw(raw_iter);
+}
+}
+
+/// Iteration main method to be called from C code