diff --git a/examples/call_between_rust_and_python.py b/examples/call_between_rust_and_python.py new file mode 100644 index 0000000000..60335d81e9 --- /dev/null +++ b/examples/call_between_rust_and_python.py @@ -0,0 +1,14 @@ +from rust_py_module import RustStruct, rust_function + +class PythonPerson: + def __init__(self, name): + self.name = name + +def python_callback(): + python_person = PythonPerson("Peter Python") + rust_object = rust_function(42, "This is a python string", python_person) + print("Printing member 'numbers' from rust struct: ", rust_object.numbers) + rust_object.print_in_rust_from_python() + +def take_string(string): + print("Calling python function from rust with string: " + string) diff --git a/examples/call_between_rust_and_python.rs b/examples/call_between_rust_and_python.rs new file mode 100644 index 0000000000..be93fb971e --- /dev/null +++ b/examples/call_between_rust_and_python.rs @@ -0,0 +1,94 @@ +use rustpython_vm::{ + pyclass, pymodule, PyObject, PyPayload, PyResult, TryFromBorrowedObject, VirtualMachine, +}; + +pub(crate) use rust_py_module::make_module; + +pub fn main() { + let interp = rustpython_vm::Interpreter::with_init(Default::default(), |vm| { + vm.add_native_modules(rustpython_stdlib::get_module_inits()); + vm.add_native_module("rust_py_module".to_owned(), Box::new(make_module)); + }); + + interp.enter(|vm| { + vm.insert_sys_path(vm.new_pyobj("examples")) + .expect("add path"); + + let module = vm.import("call_between_rust_and_python", None, 0).unwrap(); + let init_fn = module.get_attr("python_callback", vm).unwrap(); + vm.invoke(&init_fn, ()).unwrap(); + + let take_string_fn = module.get_attr("take_string", vm).unwrap(); + vm.invoke( + &take_string_fn, + (String::from("Rust string sent to python"),), + ) + .unwrap(); + }) +} + +#[pymodule] +mod rust_py_module { + use super::*; + use rustpython_vm::{builtins::PyList, convert::ToPyObject, PyObjectRef}; + + #[pyfunction] + fn rust_function( + num: i32, + s: String, + python_person: PythonPerson, + _vm: &VirtualMachine, + ) -> PyResult { + println!( + "Calling standalone rust function from python passing args: +num: {}, +string: {}, +python_person.name: {}", + num, s, python_person.name + ); + Ok(RustStruct { + numbers: NumVec(vec![1, 2, 3, 4]), + }) + } + + #[derive(Debug, Clone)] + struct NumVec(Vec); + + impl ToPyObject for NumVec { + fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef { + let list = self.0.into_iter().map(|e| vm.new_pyobj(e)).collect(); + PyList::new_ref(list, vm.as_ref()).to_pyobject(vm) + } + } + + #[pyattr] + #[pyclass(module = "rust_py_module", name = "RustStruct")] + #[derive(Debug, PyPayload)] + struct RustStruct { + numbers: NumVec, + } + + #[pyclass] + impl RustStruct { + #[pygetset] + fn numbers(&self) -> NumVec { + self.numbers.clone() + } + + #[pymethod] + fn print_in_rust_from_python(&self) { + println!("Calling a rust method from python"); + } + } + + struct PythonPerson { + name: String, + } + + impl TryFromBorrowedObject for PythonPerson { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult { + let name = obj.get_attr("name", vm)?.try_into_value::(vm)?; + Ok(PythonPerson { name }) + } + } +}