Macro cpython::py_capsule_fn
source · macro_rules! py_capsule_fn { (from $($capsmod:ident).+ import $capsname:ident as $rustmod:ident signature $( $sig: tt)* ) => { ... }; }
Expand description
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
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:
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 incpython
public API involving raw FFI pointers, such asfrom_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!)
use cpython::{PyCapsule, Python, FromPyObject, py_capsule_fn};
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.
use cpython::{PyCapsule, PyObject, PyResult, Python, py_capsule_fn};
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)) })
}