3

I'm using pyo3 to add some rust to my python project (for performance), and wanted to create a function to make adding submodules easier. My current code:

fn register_submodule(name: &str, python: Python, parent: &PyModule, funcs: Vec<?>) -> PyResult<()> {
    let name = &(parent.name()?.to_owned() + name);
    let child = PyModule::new(python, name)?;

    for func in &funcs {
        child.add_function(wrap_pyfunction!(func, child)?)?;
    }

    py_run!(python, child, format!("import sys; sys.modules[{}] = child_module", name).as_str());
    parent.add_submodule(child)?;

    Ok(())
}

I want this function to be able to take an array or vector (or whatever) containing functions that implement the #[PyFunction] macro, take any arguments of any type and return a PyResult containing any type, so I can register these to the new module. Is this possible? How would I go about doing it, or achieving a similar result? Any help would be much appreciated!

Herohtar
  • 5,347
  • 4
  • 31
  • 41
0x5DA
  • 77
  • 1
  • 5

1 Answers1

0

There is no way to do it, either no way to pass vector with different functions. Because functions in Vector may be very different, may accept different type/count of arguments (how rust will know how to call/use that functions).

The only way to achieve this is with Enums.

Create Enum with variants of all Python functions eg.

enum PyFunctionVariant {
   F1(fn(param1: i32, param2: i32) -> PyResult),
   F2(fn(param1: &str, param2: &str) -> PyResult),
   // all your function definitions
}

Change register_submodule declaration to accept Vec of PyFunctionVariant.

fn register_submodule(name: &str, python: Python, parent: &PyModule, funcs: Vec<PyFunctionVariant>) -> PyResult<()> {
   ...
}

You may also need to change this part with match, because now func is Enum not PyFunction.

for func in &funcs {
    child.add_function(wrap_pyfunction!(func, child)?)?; // Change Here
}

and use this way

let functions = vec![
   PyFunctionVariant::F1(add_int),
   PyFunctionVariant::F2(concat_str),
   // etc...
];
register_submodule("module", python, parent, functions)

Edit: There is also another way, You can use Vec<Box<dyn Any>> for passing vector of different functions. trait Any

  • could you provide code examples of how you would use those 2 functions inside the `wrap_pyfunction![]` part? I'm having trouble understanding what you mean. (i'm new to rust, so sorry if i'm missing something very obvious!) – 0x5DA Sep 11 '22 at 13:53
  • I'm not an expert in PyO3 lib, but after some research I found struct `PyFunction` there. I think changing this -> `Vec>` to `Vec – Anwsonwsymous Sep 11 '22 at 20:51
  • Sorry, didn't work. I will just add the functions from outside the function, thanks for your help. – 0x5DA Sep 15 '22 at 17:31