rust/hg-cpython/src/cindex.rs
changeset 43213 0246bbe1045d
parent 42609 326fdce22fb2
child 43959 f384d68d8ea8
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 }