comparison rust/hg-cpython/src/cindex.rs @ 43213:0246bbe1045d

rust-cpython: leverage upstreamed py_capsule_fn!() macro
author Yuya Nishihara <yuya@tcha.org>
date Sun, 13 Oct 2019 17:07:44 +0900
parents 326fdce22fb2
children f384d68d8ea8
comparison
equal deleted inserted replaced
43212:9bbe08abaf48 43213:0246bbe1045d
7 7
8 //! Bindings to use the Index defined by the parsers C extension 8 //! Bindings to use the Index defined by the parsers C extension
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 ///
32 /// This implementation of the `Graph` trait, relies on (pointers to) 29 /// This implementation of the `Graph` trait, relies on (pointers to)
33 /// - the C index object (`index` member) 30 /// - the C index object (`index` member)
59 /// the core API, that would be tied to `GILGuard` / `Python<'p>` 56 /// the core API, that would be tied to `GILGuard` / `Python<'p>`
60 /// in the case of the `cpython` crate bindings yet could leave room for other 57 /// in the case of the `cpython` crate bindings yet could leave room for other
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 }
75 72
76 impl Clone for Index { 73 impl Clone for Index {
101 0 => Ok(res), 98 0 => Ok(res),
102 _ => Err(GraphError::ParentOutOfRange(rev)), 99 _ => Err(GraphError::ParentOutOfRange(rev)),
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 }