Mercurial > hg
changeset 40965:5532823e8c18
rust-cpython: start cpython crate bindings
This changeset introduces the hg-cpython crate,
that compiles as a shared library holding a whole
Python package (mercurial.rustext), with only the empty
'ancestor' submodule for now.
Such bindings will be easier and safer to develop and maintain
that those of `hg-direct-ffi`.
They don't involve C code, only unsafe Rust that's mostly isolated
within the cpython crate.
The long-term goal would be to import the provided modules, such
as rustext.ancestor with mercurial.policy.importmod, same as
we already do with cext modules.
Differential Revision: https://phab.mercurial-scm.org/D5434
author | Georges Racinet <gracinet@anybox.fr> |
---|---|
date | Mon, 03 Dec 2018 06:52:17 +0100 |
parents | 98a0fbda8739 |
children | 1eaf62a67c1a |
files | rust/Cargo.lock rust/Cargo.toml rust/hg-cpython/Cargo.toml rust/hg-cpython/rustfmt.toml rust/hg-cpython/src/ancestors.rs rust/hg-cpython/src/exceptions.rs rust/hg-cpython/src/lib.rs |
diffstat | 7 files changed, 247 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/Cargo.lock Mon Dec 03 06:54:19 2018 +0100 +++ b/rust/Cargo.lock Mon Dec 03 06:52:17 2018 +0100 @@ -1,8 +1,42 @@ +[[package]] +name = "aho-corasick" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cfg-if" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cpython" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hg-core" version = "0.1.0" [[package]] +name = "hg-cpython" +version = "0.1.0" +dependencies = [ + "cpython 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hg-core 0.1.0", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "hgdirectffi" version = "0.1.0" dependencies = [ @@ -11,9 +45,104 @@ ] [[package]] +name = "lazy_static" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "libc" version = "0.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memchr" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "python27-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "python3-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ucd-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf8-ranges" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] +"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" +"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum cpython 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b489034e723e7f5109fecd19b719e664f89ef925be785885252469e9822fa940" +"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" +"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9" +"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56114c37d4dca82526d74009df7782a28c871ac9d36b19d4cb9e67672258527e" +"checksum python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "61e4aac43f833fd637e429506cb2ac9d7df672c4b68f2eaaa163649b7fdc0444" +"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" +"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
--- a/rust/Cargo.toml Mon Dec 03 06:54:19 2018 +0100 +++ b/rust/Cargo.toml Mon Dec 03 06:52:17 2018 +0100 @@ -1,3 +1,3 @@ [workspace] -members = ["hg-core", "hg-direct-ffi"] +members = ["hg-core", "hg-direct-ffi", "hg-cpython"] exclude = ["chg", "hgcli"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-cpython/Cargo.toml Mon Dec 03 06:52:17 2018 +0100 @@ -0,0 +1,29 @@ +[package] +name = "hg-cpython" +version = "0.1.0" +authors = ["Georges Racinet <gracinet@anybox.fr>"] + +[lib] +name='rusthg' +crate-type = ["cdylib"] + +[features] +default = ["python27", "python27-sys"] + +python27 = ["cpython/python27-sys", "cpython/extension-module-2-7"] + +[dependencies] +hg-core = { path = "../hg-core" } +libc = '*' + +[dependencies.cpython] +version = "*" +default-features = false + +[dependencies.python27-sys] +version = "0.2.1" +optional = true + +[dependencies.python3-sys] +version = "0.2.1" +optional = true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-cpython/rustfmt.toml Mon Dec 03 06:52:17 2018 +0100 @@ -0,0 +1,3 @@ +max_width = 79 +wrap_comments = true +error_on_line_overflow = true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-cpython/src/ancestors.rs Mon Dec 03 06:52:17 2018 +0100 @@ -0,0 +1,30 @@ +// ancestors.rs +// +// Copyright 2018 Georges Racinet <gracinet@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 the hg::ancestors module provided by the +//! `hg-core` crate. From Python, this will be seen as `rustext.ancestor` +use cpython::{PyDict, PyModule, PyResult, Python}; + +/// Create the module, with __package__ given from parent +pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { + let dotted_name = &format!("{}.ancestor", package); + let m = PyModule::new(py, dotted_name)?; + m.add(py, "__package__", package)?; + m.add( + py, + "__doc__", + "Generic DAG ancestor algorithms - Rust implementation", + )?; + + let sys = PyModule::import(py, "sys")?; + let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; + sys_modules.set_item(py, dotted_name, &m)?; + // Example C code (see pyexpat.c and import.c) will "give away the + // reference", but we won't because it will be consumed once the + // Rust PyObject is dropped. + Ok(m) +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-cpython/src/exceptions.rs Mon Dec 03 06:52:17 2018 +0100 @@ -0,0 +1,15 @@ +use cpython::exc::ValueError; +use cpython::{PyErr, Python}; +use hg; + +py_exception!(rustext, GraphError, ValueError); + +impl GraphError { + pub fn pynew(py: Python, inner: hg::GraphError) -> PyErr { + match inner { + hg::GraphError::ParentOutOfRange(r) => { + GraphError::new(py, ("ParentOutOfRange", r)) + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-cpython/src/lib.rs Mon Dec 03 06:52:17 2018 +0100 @@ -0,0 +1,40 @@ +// lib.rs +// +// Copyright 2018 Georges Racinet <gracinet@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. + +//! Python bindings of `hg-core` objects using the `cpython` crate. +//! Once compiled, the resulting single shared library object can be placed in +//! the `mercurial` package directly as `rustext.so` or `rustext.dll`. +//! It holds several modules, so that from the point of view of Python, +//! it behaves as the `cext` package. +//! +//! Example: +//! ``` +//! >>> from mercurial.rustext import ancestor +//! >>> ancestor.__doc__ +//! 'Generic DAG ancestor algorithms - Rust implementation' +//! ``` + +#[macro_use] +extern crate cpython; +extern crate hg; + +mod ancestors; +mod exceptions; + +py_module_initializer!(rustext, initrustext, PyInit_rustext, |py, m| { + m.add( + py, + "__doc__", + "Mercurial core concepts - Rust implementation", + )?; + + let dotted_name: String = m.get(py, "__name__")?.extract(py)?; + m.add(py, "__package__", "mercurial")?; + m.add(py, "ancestor", ancestors::init_module(py, &dotted_name)?)?; + m.add(py, "GraphError", py.get_type::<exceptions::GraphError>())?; + Ok(()) +});