##// END OF EJS Templates
rust-cpython: leverage upstreamed py_capsule_fn!() macro
Yuya Nishihara -
r43484:0246bbe1 default
parent child Browse files
Show More
@@ -9,23 +9,20 b''
9 //!
9 //!
10 //! Ideally, we should use an Index entirely implemented in Rust,
10 //! Ideally, we should use an Index entirely implemented in Rust,
11 //! but this will take some time to get there.
11 //! but this will take some time to get there.
12 #[cfg(feature = "python27")]
13 use python27_sys as python_sys;
14 #[cfg(feature = "python3")]
15 use python3_sys as python_sys;
16
12
17 use cpython::{PyClone, PyErr, PyObject, PyResult, Python};
13 use cpython::{PyClone, PyObject, PyResult, Python};
18 use hg::{Graph, GraphError, Revision, WORKING_DIRECTORY_REVISION};
14 use hg::{Graph, GraphError, Revision, WORKING_DIRECTORY_REVISION};
19 use libc::c_int;
15 use libc::c_int;
20 use python_sys::PyCapsule_Import;
21 use std::ffi::CStr;
22 use std::mem::transmute;
23
16
24 type IndexParentsFn = unsafe extern "C" fn(
17 py_capsule_fn!(
25 index: *mut python_sys::PyObject,
18 from mercurial.cext.parsers import index_get_parents_CAPI
26 rev: c_int,
19 as get_parents_capi
27 ps: *mut [c_int; 2],
20 signature (
28 ) -> c_int;
21 index: *mut RawPyObject,
22 rev: c_int,
23 ps: *mut [c_int; 2],
24 ) -> c_int
25 );
29
26
30 /// A `Graph` backed up by objects and functions from revlog.c
27 /// A `Graph` backed up by objects and functions from revlog.c
31 ///
28 ///
@@ -61,14 +58,14 b' type IndexParentsFn = unsafe extern "C" '
61 /// mechanisms in other contexts.
58 /// mechanisms in other contexts.
62 pub struct Index {
59 pub struct Index {
63 index: PyObject,
60 index: PyObject,
64 parents: IndexParentsFn,
61 parents: get_parents_capi::CapsuleFn,
65 }
62 }
66
63
67 impl Index {
64 impl Index {
68 pub fn new(py: Python, index: PyObject) -> PyResult<Self> {
65 pub fn new(py: Python, index: PyObject) -> PyResult<Self> {
69 Ok(Index {
66 Ok(Index {
70 index: index,
67 index: index,
71 parents: decapsule_parents_fn(py)?,
68 parents: get_parents_capi::retrieve(py)?,
72 })
69 })
73 }
70 }
74 }
71 }
@@ -103,31 +100,3 b' impl Graph for Index {'
103 }
100 }
104 }
101 }
105 }
102 }
106
107 /// Return the `index_get_parents` function of the parsers C Extension module.
108 ///
109 /// A pointer to the function is stored in the `parsers` module as a
110 /// standard [Python capsule](https://docs.python.org/2/c-api/capsule.html).
111 ///
112 /// This function retrieves the capsule and casts the function pointer
113 ///
114 /// Casting function pointers is one of the rare cases of
115 /// legitimate use cases of `mem::transmute()` (see
116 /// https://doc.rust-lang.org/std/mem/fn.transmute.html of
117 /// `mem::transmute()`.
118 /// It is inappropriate for architectures where
119 /// function and data pointer sizes differ (so-called "Harvard
120 /// architectures"), but these are nowadays mostly DSPs
121 /// and microcontrollers, hence out of our scope.
122 fn decapsule_parents_fn(py: Python) -> PyResult<IndexParentsFn> {
123 unsafe {
124 let caps_name = CStr::from_bytes_with_nul_unchecked(
125 b"mercurial.cext.parsers.index_get_parents_CAPI\0",
126 );
127 let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0);
128 if from_caps.is_null() {
129 return Err(PyErr::fetch(py));
130 }
131 Ok(transmute(from_caps))
132 }
133 }
@@ -22,14 +22,7 b' use hg::{'
22 StateMap,
22 StateMap,
23 };
23 };
24 use libc::{c_char, c_int};
24 use libc::{c_char, c_int};
25 #[cfg(feature = "python27")]
26 use python27_sys as python_sys;
27 #[cfg(feature = "python3")]
28 use python3_sys as python_sys;
29 use python_sys::PyCapsule_Import;
30 use std::convert::TryFrom;
25 use std::convert::TryFrom;
31 use std::ffi::CStr;
32 use std::mem::transmute;
33
26
34 // C code uses a custom `dirstate_tuple` type, checks in multiple instances
27 // C code uses a custom `dirstate_tuple` type, checks in multiple instances
35 // for this type, and raises a Python `Exception` if the check does not pass.
28 // for this type, and raises a Python `Exception` if the check does not pass.
@@ -37,34 +30,23 b' use std::mem::transmute;'
37 // would be a good idea in the near future to remove it entirely to allow
30 // would be a good idea in the near future to remove it entirely to allow
38 // for a pure Python tuple of the same effective structure to be used,
31 // for a pure Python tuple of the same effective structure to be used,
39 // rendering this type and the capsule below useless.
32 // rendering this type and the capsule below useless.
40 type MakeDirstateTupleFn = unsafe extern "C" fn(
33 py_capsule_fn!(
41 state: c_char,
34 from mercurial.cext.parsers import make_dirstate_tuple_CAPI
42 mode: c_int,
35 as make_dirstate_tuple_capi
43 size: c_int,
36 signature (
44 mtime: c_int,
37 state: c_char,
45 ) -> *mut python_sys::PyObject;
38 mode: c_int,
46
39 size: c_int,
47 // This is largely a copy/paste from cindex.rs, pending the merge of a
40 mtime: c_int,
48 // `py_capsule_fn!` macro in the rust-cpython project:
41 ) -> *mut RawPyObject
49 // https://github.com/dgrunwald/rust-cpython/pull/169
42 );
50 fn decapsule_make_dirstate_tuple(py: Python) -> PyResult<MakeDirstateTupleFn> {
51 unsafe {
52 let caps_name = CStr::from_bytes_with_nul_unchecked(
53 b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0",
54 );
55 let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0);
56 if from_caps.is_null() {
57 return Err(PyErr::fetch(py));
58 }
59 Ok(transmute(from_caps))
60 }
61 }
62
43
63 pub fn make_dirstate_tuple(
44 pub fn make_dirstate_tuple(
64 py: Python,
45 py: Python,
65 entry: &DirstateEntry,
46 entry: &DirstateEntry,
66 ) -> PyResult<PyObject> {
47 ) -> PyResult<PyObject> {
67 let make = decapsule_make_dirstate_tuple(py)?;
48 // might be silly to retrieve capsule function in hot loop
49 let make = make_dirstate_tuple_capi::retrieve(py)?;
68
50
69 let &DirstateEntry {
51 let &DirstateEntry {
70 state,
52 state,
General Comments 0
You need to be logged in to leave comments. Login now