# HG changeset patch # User Yuya Nishihara # Date 1570954064 -32400 # Node ID 0246bbe1045d7064755d63967146c445fe92a3cd # Parent 9bbe08abaf489ed25a61962caf56669ac0d80a60 rust-cpython: leverage upstreamed py_capsule_fn!() macro diff -r 9bbe08abaf48 -r 0246bbe1045d rust/hg-cpython/src/cindex.rs --- a/rust/hg-cpython/src/cindex.rs Sun Oct 13 17:05:09 2019 +0900 +++ b/rust/hg-cpython/src/cindex.rs Sun Oct 13 17:07:44 2019 +0900 @@ -9,23 +9,20 @@ //! //! Ideally, we should use an Index entirely implemented in Rust, //! but this will take some time to get there. -#[cfg(feature = "python27")] -use python27_sys as python_sys; -#[cfg(feature = "python3")] -use python3_sys as python_sys; -use cpython::{PyClone, PyErr, PyObject, PyResult, Python}; +use cpython::{PyClone, PyObject, PyResult, Python}; use hg::{Graph, GraphError, Revision, WORKING_DIRECTORY_REVISION}; use libc::c_int; -use python_sys::PyCapsule_Import; -use std::ffi::CStr; -use std::mem::transmute; -type IndexParentsFn = unsafe extern "C" fn( - index: *mut python_sys::PyObject, - rev: c_int, - ps: *mut [c_int; 2], -) -> c_int; +py_capsule_fn!( + from mercurial.cext.parsers import index_get_parents_CAPI + as get_parents_capi + signature ( + index: *mut RawPyObject, + rev: c_int, + ps: *mut [c_int; 2], + ) -> c_int +); /// A `Graph` backed up by objects and functions from revlog.c /// @@ -61,14 +58,14 @@ /// mechanisms in other contexts. pub struct Index { index: PyObject, - parents: IndexParentsFn, + parents: get_parents_capi::CapsuleFn, } impl Index { pub fn new(py: Python, index: PyObject) -> PyResult { Ok(Index { index: index, - parents: decapsule_parents_fn(py)?, + parents: get_parents_capi::retrieve(py)?, }) } } @@ -103,31 +100,3 @@ } } } - -/// Return the `index_get_parents` function of the parsers C Extension module. -/// -/// A pointer to the function is stored in the `parsers` module as a -/// standard [Python capsule](https://docs.python.org/2/c-api/capsule.html). -/// -/// This function retrieves the capsule and casts the function pointer -/// -/// Casting function pointers is one of the rare cases of -/// legitimate use cases of `mem::transmute()` (see -/// https://doc.rust-lang.org/std/mem/fn.transmute.html of -/// `mem::transmute()`. -/// It is inappropriate for architectures where -/// function and data pointer sizes differ (so-called "Harvard -/// architectures"), but these are nowadays mostly DSPs -/// and microcontrollers, hence out of our scope. -fn decapsule_parents_fn(py: Python) -> PyResult { - unsafe { - let caps_name = CStr::from_bytes_with_nul_unchecked( - b"mercurial.cext.parsers.index_get_parents_CAPI\0", - ); - let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0); - if from_caps.is_null() { - return Err(PyErr::fetch(py)); - } - Ok(transmute(from_caps)) - } -} diff -r 9bbe08abaf48 -r 0246bbe1045d rust/hg-cpython/src/dirstate.rs --- a/rust/hg-cpython/src/dirstate.rs Sun Oct 13 17:05:09 2019 +0900 +++ b/rust/hg-cpython/src/dirstate.rs Sun Oct 13 17:07:44 2019 +0900 @@ -22,14 +22,7 @@ StateMap, }; use libc::{c_char, c_int}; -#[cfg(feature = "python27")] -use python27_sys as python_sys; -#[cfg(feature = "python3")] -use python3_sys as python_sys; -use python_sys::PyCapsule_Import; use std::convert::TryFrom; -use std::ffi::CStr; -use std::mem::transmute; // C code uses a custom `dirstate_tuple` type, checks in multiple instances // for this type, and raises a Python `Exception` if the check does not pass. @@ -37,34 +30,23 @@ // would be a good idea in the near future to remove it entirely to allow // for a pure Python tuple of the same effective structure to be used, // rendering this type and the capsule below useless. -type MakeDirstateTupleFn = unsafe extern "C" fn( - state: c_char, - mode: c_int, - size: c_int, - mtime: c_int, -) -> *mut python_sys::PyObject; - -// This is largely a copy/paste from cindex.rs, pending the merge of a -// `py_capsule_fn!` macro in the rust-cpython project: -// https://github.com/dgrunwald/rust-cpython/pull/169 -fn decapsule_make_dirstate_tuple(py: Python) -> PyResult { - unsafe { - let caps_name = CStr::from_bytes_with_nul_unchecked( - b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0", - ); - let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0); - if from_caps.is_null() { - return Err(PyErr::fetch(py)); - } - Ok(transmute(from_caps)) - } -} +py_capsule_fn!( + from mercurial.cext.parsers import make_dirstate_tuple_CAPI + as make_dirstate_tuple_capi + signature ( + state: c_char, + mode: c_int, + size: c_int, + mtime: c_int, + ) -> *mut RawPyObject +); pub fn make_dirstate_tuple( py: Python, entry: &DirstateEntry, ) -> PyResult { - let make = decapsule_make_dirstate_tuple(py)?; + // might be silly to retrieve capsule function in hot loop + let make = make_dirstate_tuple_capi::retrieve(py)?; let &DirstateEntry { state,