# HG changeset patch # User Georges Racinet <graci...@anybox.fr> # 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 <graci...@anybox.fr>"] + +[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 +0000 +++ b/mercurial/rust/src/cpython.rs Thu Sep 27 16:51:36 2018 +0200 @@ -0,0 +1,170 @@ +// Copyright 2018 Georges Racinet <graci...@anybox.fr> +// +// 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(&self, 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, + &mut 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<CIndex> 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<Index> { + let v: Vec<i64> = + 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), + &v, + stoprev, + inclb, + ))) +} + +/// Deallocator to be called from C code +#[no_mangle] +pub extern "C" fn rustlazyancestors_drop( + raw_iter: *mut AncestorsIterator<Index>, +) { + unsafe { + Box::from_raw(raw_iter); + } +} + +/// Iteration main method to be called from C code +/// +/// We use -1 to mean the end of iteration +#[no_mangle] +pub extern "C" fn rustlazyancestors_next( + iter_raw: *mut AncestorsIterator<Index>, +) -> i32 { + let iter = unsafe { &mut *iter_raw }; + match iter.next() { + Some(i) => i, + None => -1, + } +} + +#[cfg(test)] +mod tests { + use std::thread; + use super::*; + + #[derive(Clone, Debug)] + enum Stub { + Some, + } + + impl Graph for Stub { + fn parents(&self, _i: i32) -> (i32, i32) { + (1, 2) + } + } + + fn it_init_raw( + graph: &Stub, + initrevs: &Vec<i64>, + stoprev: i64, + ) -> *mut AncestorsIterator<Stub> { + // inclusive=true forces to push immediately stuff in the binary heap + Box::into_raw(Box::new(AncestorsIterator::new( + graph.clone(), + initrevs, + stoprev, + true, + ))) + } + + fn it_next_raw(iter_raw: *mut AncestorsIterator<Stub>) -> i32 { + let iter = unsafe { &mut *iter_raw }; + let res = match iter.next() { + Some(i) => i, + None => -1, + }; + res + } + + #[test] + // Test what happens when we init an Iterator as with the exposed C ABI + // and try to use it afterwards + // We spawn new threads, in order to make memory consistency harder + fn test_back_and_forth() { + let handler = thread::spawn( + || it_init_raw(&Stub::Some, &vec![11, 13], 0) as u64, + ); + let iter_raw = handler.join().unwrap() as *mut AncestorsIterator<Stub>; + assert_eq!(it_next_raw(iter_raw), 13); + assert_eq!(it_next_raw(iter_raw), 11); + unsafe { Box::from_raw(iter_raw) }; + } +} diff -r d8c9571755a6 -r de88c0951256 mercurial/rust/src/lib.rs --- a/mercurial/rust/src/lib.rs Thu Sep 27 17:03:16 2018 +0200 +++ b/mercurial/rust/src/lib.rs Thu Sep 27 16:51:36 2018 +0200 @@ -2,6 +2,9 @@ // // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. - mod ancestors; pub use ancestors::{AncestorsIterator, Graph}; + +mod cpython; +pub use cpython::{rustlazyancestors_init, rustlazyancestors_drop, + rustlazyancestors_next}; _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel