Patchwork [6,of,7] rust-cpython: leverage upstreamed py_capsule_fn!() macro

login
register
mail settings
Submitter Yuya Nishihara
Date Oct. 13, 2019, 1:41 p.m.
Message ID <7ac435844d990e027d8b.1570974102@mimosa>
Download mbox | patch
Permalink /patch/42300/
State New
Headers show

Comments

Yuya Nishihara - Oct. 13, 2019, 1:41 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1570954064 -32400
#      Sun Oct 13 17:07:44 2019 +0900
# Node ID 7ac435844d990e027d8b589909ca42d17a89b6b4
# Parent  7073183d7ec824b6b3686b41b6c0a98d089a6447
rust-cpython: leverage upstreamed py_capsule_fn!() macro

Patch

diff --git a/rust/hg-cpython/src/cindex.rs b/rust/hg-cpython/src/cindex.rs
--- a/rust/hg-cpython/src/cindex.rs
+++ b/rust/hg-cpython/src/cindex.rs
@@ -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 @@  type IndexParentsFn = unsafe extern "C" 
 /// 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<Self> {
         Ok(Index {
             index: index,
-            parents: decapsule_parents_fn(py)?,
+            parents: get_parents_capi::retrieve(py)?,
         })
     }
 }
@@ -103,31 +100,3 @@  impl Graph for Index {
         }
     }
 }
-
-/// 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<IndexParentsFn> {
-    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 --git a/rust/hg-cpython/src/dirstate.rs b/rust/hg-cpython/src/dirstate.rs
--- a/rust/hg-cpython/src/dirstate.rs
+++ b/rust/hg-cpython/src/dirstate.rs
@@ -22,14 +22,7 @@  use hg::{
     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 @@  use std::mem::transmute;
 // 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<MakeDirstateTupleFn> {
-    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<PyObject> {
-    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,