Replies: 1 comment
-
I've been exploring this a bit further and stumbled across fn rust_func(foo: Foo) {
println!("{foo:?}");
}
#[pyfunction]
fn get_callback_in_capsule(py: Python<'_>) -> PyObject {
let ptr: fn(Foo) = rust_func;
let name = CString::new("rust_func").unwrap();
PyCapsule::new(py, ptr, Some(name)).unwrap().into()}
#[pyfunction]
fn call_callback_in_capsule(object: PyObject, foo: Foo) -> PyResult<()> {
Python::with_gil(|py| {
let capsule = object.downcast_bound::<PyCapsule>(py)?;
let f = unsafe { capsule.reference::<fn(Foo)>()? };
// Call with default Foo (no marshalling)
f(Foo::default());
// Call with value from Python (already marshalled)
f(foo);
Ok(())
})
} This seems to work as a low-level workaround — the unsafe block is obviously something to be careful about, but as long as the capsule contains exactly what I expect, it's viable. I also need to find a way to export the function to Python, so it can be called in Python, and only retrieve the original function as part of the capsule when I pass it as a callback to Rust. Does this seem like a reasonable direction? Is there a better/more idiomatic way to do this in PyO3? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi all 👋
I'm currently working on a project using PyO3 in which I export Rust functions to Python that can then be passed back as callbacks to other exported Rust functions. In this setup, I'm wondering if there's a way to avoid the overhead of Rust → Python → Rust conversions, specifically in cases where I know the exact shape of the function being called.
Minimal Example
Let’s say I have a Rust struct
Foo
and a functionjust_print_foo
exposed to Python:Now, I define another function that receives a Python callback and calls it with a
Foo
:This works fine, but involves two marshaling steps (Rust → Python and back). What I’m wondering is: if I know ahead of time that the callback is actually a Rust function (e.g.,
just_print_foo
), is there a way to "recover" that original Rust function — perhaps via downcasting or some other mechanism — and bypass Python entirely?Hypothetical API
Something like this is what I have in mind:
I understand this might be tricky (or not even possible), given how PyO3 handles wrapping and registration of functions, but is there any current mechanism or planned feature that could help in cases like this?
Apologies if this is a naive question — I’m still fairly new to PyO3 and getting familiar with how these internals work. I also didn't find any similar discussions, so apologies if this has been asked already – happy for a link to prior discussions as well.
Thanks in advance for any insights!
Beta Was this translation helpful? Give feedback.
All reactions