[][src]Macro cpython::py_capsule_fn

macro_rules! py_capsule_fn {
    (from $($capsmod:ident).+ import $capsname:ident as $rustmod:ident signature $( $sig: tt)* ) => { ... };
}

Macro to retrieve a function pointer capsule.

This is not suitable for architectures where the sizes of function and data pointers differ. For general explanations about capsules, see PyCapsule.

Usage

This example is not tested
   py_capsule_fn!(from some.python.module import capsulename as rustmodule
                      signature (args) -> ret_type)

Similarly to py_capsule!, the macro defines

  • a Rust module according to the name provided by the caller (here, rustmodule)
  • a type alias for the given signature
  • a retrieval function:
This example is not tested
mod $rustmod {
    pub type CapsuleFn = unsafe extern "C" (args) -> ret_type ;
    pub unsafe fn retrieve<'a>(py: Python) -> PyResult<CapsuleFn) { ... }
}
  • a RawPyObject type suitable for signatures that involve Python C objects; it can be used in cpython public API involving raw FFI pointers, such as from_owned_ptr.

The first call to retrieve() is cached for subsequent calls.

Examples

Full example with primitive types

There is in the Python library no capsule enclosing a function pointer directly, although the documentation presents it as a valid use-case. For this example, we'll therefore have to create one, using the PyCapsule constructor, and to set it in an existing module (not to imply that a real extension should follow that example and set capsules in modules they don't define!)

#[macro_use] extern crate cpython;
extern crate libc;
use cpython::{PyCapsule, Python, FromPyObject};
use libc::{c_int, c_void};

extern "C" fn inc(a: c_int) -> c_int {
    a + 1
}

/// for testing purposes, stores a capsule named `sys.capsfn`` pointing to `inc()`.
fn create_capsule() {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let pymod = py.import("sys").unwrap();
    let caps = PyCapsule::new(py, inc as *const c_void, "sys.capsfn").unwrap();
    pymod.add(py, "capsfn", caps).unwrap();
 }

py_capsule_fn!(from sys import capsfn as capsmod signature (a: c_int) -> c_int);

// One could, e.g., reexport if needed:
pub use capsmod::CapsuleFn;

fn retrieve_use_capsule() {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let fun = capsmod::retrieve(py).unwrap();
    assert_eq!( unsafe { fun(1) }, 2);

    // let's demonstrate the (reexported) function type
    let g: CapsuleFn = fun;
}

fn main() {
    create_capsule();
    retrieve_use_capsule();
    // second call uses the cached function pointer
    retrieve_use_capsule();
}

With Python objects

In this example, we lend a Python object and receive a new one of which we take ownership.

#[macro_use] extern crate cpython;
use cpython::{PyCapsule, PyObject, PyResult, Python};

py_capsule_fn!(from some.mod import capsfn as capsmod
    signature (raw: *mut RawPyObject) -> *mut RawPyObject);

fn retrieve_use_capsule(py: Python, obj: PyObject) -> PyResult<PyObject> {
    let fun = capsmod::retrieve(py)?;
    let raw = obj.as_ptr();
    Ok(unsafe { PyObject::from_owned_ptr(py, fun(raw)) })
}