Change add_function, ensure static docstrings.
Change add_function to take `&PyCFunction` instead of a wrapper fn and ensure that dostrings of functions are `&'static str`.
This commit is contained in:
parent
be877d133f
commit
22881a3c2f
|
@ -67,7 +67,7 @@ fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
|||
/// A Python module implemented in Rust.
|
||||
#[pymodule]
|
||||
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(sum_as_string))?;
|
||||
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -215,29 +215,29 @@ impl TzClass {
|
|||
|
||||
#[pymodule]
|
||||
fn datetime(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(make_date))?;
|
||||
m.add_function(wrap_pyfunction!(get_date_tuple))?;
|
||||
m.add_function(wrap_pyfunction!(date_from_timestamp))?;
|
||||
m.add_function(wrap_pyfunction!(make_time))?;
|
||||
m.add_function(wrap_pyfunction!(get_time_tuple))?;
|
||||
m.add_function(wrap_pyfunction!(make_delta))?;
|
||||
m.add_function(wrap_pyfunction!(get_delta_tuple))?;
|
||||
m.add_function(wrap_pyfunction!(make_datetime))?;
|
||||
m.add_function(wrap_pyfunction!(get_datetime_tuple))?;
|
||||
m.add_function(wrap_pyfunction!(datetime_from_timestamp))?;
|
||||
m.add_function(wrap_pyfunction!(make_date, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(get_date_tuple, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(date_from_timestamp, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(make_time, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(get_time_tuple, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(make_delta, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(get_delta_tuple, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(make_datetime, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(get_datetime_tuple, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(datetime_from_timestamp, m)?)?;
|
||||
|
||||
// Python 3.6+ functions
|
||||
#[cfg(Py_3_6)]
|
||||
{
|
||||
m.add_function(wrap_pyfunction!(time_with_fold))?;
|
||||
m.add_function(wrap_pyfunction!(time_with_fold, m)?)?;
|
||||
#[cfg(not(PyPy))]
|
||||
{
|
||||
m.add_function(wrap_pyfunction!(get_time_tuple_fold))?;
|
||||
m.add_function(wrap_pyfunction!(get_datetime_tuple_fold))?;
|
||||
m.add_function(wrap_pyfunction!(get_time_tuple_fold, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(get_datetime_tuple_fold, m)?)?;
|
||||
}
|
||||
}
|
||||
|
||||
m.add_function(wrap_pyfunction!(issue_219))?;
|
||||
m.add_function(wrap_pyfunction!(issue_219, m)?)?;
|
||||
m.add_class::<TzClass>()?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -31,7 +31,7 @@ fn double(x: i32) -> i32 {
|
|||
|
||||
#[pymodule]
|
||||
fn othermod(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double))?;
|
||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
||||
|
||||
m.add_class::<ModClass>()?;
|
||||
|
||||
|
|
|
@ -56,8 +56,8 @@ fn count_line(line: &str, needle: &str) -> usize {
|
|||
#[pymodule]
|
||||
fn word_count(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
m.add_wrapped(wrap_pyfunction!(search))?;
|
||||
m.add_function(wrap_pyfunction!(search_sequential))?;
|
||||
m.add_function(wrap_pyfunction!(search_sequential_allow_threads))?;
|
||||
m.add_function(wrap_pyfunction!(search_sequential, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(search_sequential_allow_threads, m)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ fn double(x: usize) -> usize {
|
|||
|
||||
#[pymodule]
|
||||
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double)).unwrap();
|
||||
m.add_function(wrap_pyfunction!(double, m)?).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ fn num_kwds(kwds: Option<&PyDict>) -> usize {
|
|||
|
||||
#[pymodule]
|
||||
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(num_kwds)).unwrap();
|
||||
m.add_function(wrap_pyfunction!(num_kwds, m)?).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ fn pyfunction_with_module(module: &PyModule) -> PyResult<&str> {
|
|||
|
||||
#[pymodule]
|
||||
fn module_with_fn(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(pyfunction_with_module))
|
||||
m.add_function(wrap_pyfunction!(pyfunction_with_module, m)?)
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
|
|
|
@ -73,7 +73,7 @@ fn subfunction() -> String {
|
|||
}
|
||||
|
||||
fn init_submodule(module: &PyModule) -> PyResult<()> {
|
||||
module.add_function(wrap_pyfunction!(subfunction))?;
|
||||
module.add_function(wrap_pyfunction!(subfunction, module)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -488,7 +488,7 @@ pub struct UserModel {
|
|||
#[pymodule]
|
||||
fn trait_exposure(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_class::<UserModel>()?;
|
||||
m.add_function(wrap_pyfunction!(solve_wrapper))?;
|
||||
m.add_function(wrap_pyfunction!(solve_wrapper, m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) -> syn::Result<()> {
|
|||
let item: syn::ItemFn = syn::parse_quote! {
|
||||
fn block_wrapper() {
|
||||
#function_to_python
|
||||
#module_name.add_function(&#function_wrapper_ident)?;
|
||||
#module_name.add_function(#function_wrapper_ident(#module_name)?)?;
|
||||
}
|
||||
};
|
||||
stmts.extend(item.block.stmts.into_iter());
|
||||
|
@ -210,11 +210,9 @@ pub fn add_fn_to_module(
|
|||
Ok(quote! {
|
||||
#wrapper
|
||||
fn #function_wrapper_ident<'a>(
|
||||
args: impl Into<pyo3::derive_utils::WrapPyFunctionArguments<'a>>
|
||||
args: impl Into<pyo3::derive_utils::PyFunctionArguments<'a>>
|
||||
) -> pyo3::PyResult<&'a pyo3::types::PyCFunction> {
|
||||
let arg = args.into();
|
||||
let (py, maybe_module) = arg.into_py_and_maybe_module();
|
||||
pyo3::types::PyCFunction::new_with_keywords(#wrapper_ident, stringify!(#python_name), #doc, maybe_module, py)
|
||||
pyo3::types::PyCFunction::new_with_keywords(#wrapper_ident, stringify!(#python_name), #doc, args.into())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -209,17 +209,16 @@ where
|
|||
}
|
||||
|
||||
/// Enum to abstract over the arguments of Python function wrappers.
|
||||
#[doc(hidden)]
|
||||
pub enum WrapPyFunctionArguments<'a> {
|
||||
pub enum PyFunctionArguments<'a> {
|
||||
Python(Python<'a>),
|
||||
PyModule(&'a PyModule),
|
||||
}
|
||||
|
||||
impl<'a> WrapPyFunctionArguments<'a> {
|
||||
impl<'a> PyFunctionArguments<'a> {
|
||||
pub fn into_py_and_maybe_module(self) -> (Python<'a>, Option<&'a PyModule>) {
|
||||
match self {
|
||||
WrapPyFunctionArguments::Python(py) => (py, None),
|
||||
WrapPyFunctionArguments::PyModule(module) => {
|
||||
PyFunctionArguments::Python(py) => (py, None),
|
||||
PyFunctionArguments::PyModule(module) => {
|
||||
let py = module.py();
|
||||
(py, Some(module))
|
||||
}
|
||||
|
@ -227,14 +226,14 @@ impl<'a> WrapPyFunctionArguments<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Python<'a>> for WrapPyFunctionArguments<'a> {
|
||||
fn from(py: Python<'a>) -> WrapPyFunctionArguments<'a> {
|
||||
WrapPyFunctionArguments::Python(py)
|
||||
impl<'a> From<Python<'a>> for PyFunctionArguments<'a> {
|
||||
fn from(py: Python<'a>) -> PyFunctionArguments<'a> {
|
||||
PyFunctionArguments::Python(py)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PyModule> for WrapPyFunctionArguments<'a> {
|
||||
fn from(module: &'a PyModule) -> WrapPyFunctionArguments<'a> {
|
||||
WrapPyFunctionArguments::PyModule(module)
|
||||
impl<'a> From<&'a PyModule> for PyFunctionArguments<'a> {
|
||||
fn from(module: &'a PyModule) -> PyFunctionArguments<'a> {
|
||||
PyFunctionArguments::PyModule(module)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
//! #[pymodule]
|
||||
//! /// A Python module implemented in Rust.
|
||||
//! fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
//! m.add_function(wrap_pyfunction!(sum_as_string))?;
|
||||
//! m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
|
@ -218,6 +218,10 @@ macro_rules! wrap_pyfunction {
|
|||
($function_name: ident) => {{
|
||||
&pyo3::paste::expr! { [<__pyo3_get_function_ $function_name>] }
|
||||
}};
|
||||
|
||||
($function_name: ident, $arg: expr) => {
|
||||
pyo3::wrap_pyfunction!($function_name)(pyo3::derive_utils::PyFunctionArguments::from($arg))
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the function that is called in the C-FFI.
|
||||
|
|
|
@ -134,7 +134,7 @@ impl<'p> Python<'p> {
|
|||
/// let gil = Python::acquire_gil();
|
||||
/// let py = gil.python();
|
||||
/// let m = PyModule::new(py, "pcount").unwrap();
|
||||
/// m.add_function(wrap_pyfunction!(parallel_count)).unwrap();
|
||||
/// m.add_function(wrap_pyfunction!(parallel_count, m).unwrap()).unwrap();
|
||||
/// let locals = [("pcount", m)].into_py_dict(py);
|
||||
/// py.run(r#"
|
||||
/// s = ["Flow", "my", "tears", "the", "Policeman", "Said"]
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::ffi::{CStr, CString};
|
||||
|
||||
use crate::derive_utils::PyFunctionArguments;
|
||||
use crate::exceptions::PyValueError;
|
||||
use crate::prelude::*;
|
||||
use crate::{class, ffi, AsPyPointer, PyMethodDef, PyMethodType};
|
||||
use crate::{class, ffi, AsPyPointer, PyMethodType};
|
||||
|
||||
/// Represents a builtin Python function object.
|
||||
#[repr(transparent)]
|
||||
|
@ -13,54 +16,47 @@ impl PyCFunction {
|
|||
pub fn new_with_keywords<'a>(
|
||||
fun: ffi::PyCFunctionWithKeywords,
|
||||
name: &str,
|
||||
doc: &str,
|
||||
module: Option<&'a PyModule>,
|
||||
py: Python<'a>,
|
||||
doc: &'static str,
|
||||
py_or_module: PyFunctionArguments<'a>,
|
||||
) -> PyResult<&'a PyCFunction> {
|
||||
let fun = PyMethodType::PyCFunctionWithKeywords(fun);
|
||||
Self::new_(fun, name, doc, module, py)
|
||||
Self::new_(fun, name, doc, py_or_module)
|
||||
}
|
||||
|
||||
/// Create a new built-in function without keywords.
|
||||
pub fn new<'a>(
|
||||
fun: ffi::PyCFunction,
|
||||
name: &str,
|
||||
doc: &str,
|
||||
module: Option<&'a PyModule>,
|
||||
py: Python<'a>,
|
||||
doc: &'static str,
|
||||
py_or_module: PyFunctionArguments<'a>,
|
||||
) -> PyResult<&'a PyCFunction> {
|
||||
let fun = PyMethodType::PyCFunction(fun);
|
||||
Self::new_(fun, name, doc, module, py)
|
||||
Self::new_(fun, name, doc, py_or_module)
|
||||
}
|
||||
|
||||
fn new_<'a>(
|
||||
fun: class::PyMethodType,
|
||||
name: &str,
|
||||
doc: &str,
|
||||
module: Option<&'a PyModule>,
|
||||
py: Python<'a>,
|
||||
doc: &'static str,
|
||||
py_or_module: PyFunctionArguments<'a>,
|
||||
) -> PyResult<&'a PyCFunction> {
|
||||
let name = name.to_string();
|
||||
let name: &'static str = Box::leak(name.into_boxed_str());
|
||||
// this is ugly but necessary since `PyMethodDef::ml_doc` is &str and not `CStr`
|
||||
let doc = if doc.ends_with('\0') {
|
||||
doc.to_string()
|
||||
} else {
|
||||
format!("{}\0", doc)
|
||||
};
|
||||
let doc: &'static str = Box::leak(doc.into_boxed_str());
|
||||
let def = match &fun {
|
||||
PyMethodType::PyCFunction(_) => PyMethodDef {
|
||||
ml_name: name,
|
||||
ml_meth: fun,
|
||||
let (py, module) = py_or_module.into_py_and_maybe_module();
|
||||
let doc: &'static CStr = CStr::from_bytes_with_nul(doc.as_bytes())
|
||||
.map_err(|_| PyValueError::py_err("docstring must end with NULL byte."))?;
|
||||
let name = CString::new(name.as_bytes())
|
||||
.map_err(|_| PyValueError::py_err("Function name cannot contain contain NULL byte."))?;
|
||||
let def = match fun {
|
||||
PyMethodType::PyCFunction(fun) => ffi::PyMethodDef {
|
||||
ml_name: name.into_raw() as _,
|
||||
ml_meth: Some(fun),
|
||||
ml_flags: ffi::METH_VARARGS,
|
||||
ml_doc: doc,
|
||||
ml_doc: doc.as_ptr() as _,
|
||||
},
|
||||
PyMethodType::PyCFunctionWithKeywords(_) => PyMethodDef {
|
||||
ml_name: name,
|
||||
ml_meth: fun,
|
||||
PyMethodType::PyCFunctionWithKeywords(fun) => ffi::PyMethodDef {
|
||||
ml_name: name.into_raw() as _,
|
||||
ml_meth: Some(unsafe { std::mem::transmute(fun) }),
|
||||
ml_flags: ffi::METH_VARARGS | ffi::METH_KEYWORDS,
|
||||
ml_doc: doc,
|
||||
ml_doc: doc.as_ptr() as _,
|
||||
},
|
||||
_ => {
|
||||
return Err(PyValueError::py_err(
|
||||
|
@ -68,7 +64,6 @@ impl PyCFunction {
|
|||
))
|
||||
}
|
||||
};
|
||||
let def = def.as_method_def();
|
||||
let (mod_ptr, module_name) = if let Some(m) = module {
|
||||
let mod_ptr = m.as_ptr();
|
||||
let name = m.name()?.into_py(py);
|
||||
|
|
|
@ -256,7 +256,7 @@ impl PyModule {
|
|||
/// }
|
||||
/// #[pymodule]
|
||||
/// fn double_mod(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||
/// module.add_function(pyo3::wrap_pyfunction!(double))
|
||||
/// module.add_function(pyo3::wrap_pyfunction!(double, module)?)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
@ -270,16 +270,11 @@ impl PyModule {
|
|||
/// }
|
||||
/// #[pymodule]
|
||||
/// fn double_mod(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||
/// module.add("also_double", pyo3::wrap_pyfunction!(double)(module)?)
|
||||
/// module.add("also_double", pyo3::wrap_pyfunction!(double, module)?)
|
||||
/// }
|
||||
/// ```
|
||||
pub fn add_function<'a>(
|
||||
&'a self,
|
||||
wrapper: &impl Fn(&'a Self) -> PyResult<&'a PyCFunction>,
|
||||
) -> PyResult<()> {
|
||||
let function = wrapper(self)?;
|
||||
let name = function.getattr("__name__")?;
|
||||
let name = name.extract()?;
|
||||
self.add(name, function)
|
||||
pub fn add_function<'a>(&'a self, fun: &'a PyCFunction) -> PyResult<()> {
|
||||
let name = fun.getattr("__name__")?.extract()?;
|
||||
self.add(name, fun)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,8 +65,8 @@ fn module_with_functions(_py: Python, m: &PyModule) -> PyResult<()> {
|
|||
|
||||
m.add("foo", "bar").unwrap();
|
||||
|
||||
m.add_function(wrap_pyfunction!(double)).unwrap();
|
||||
m.add("also_double", wrap_pyfunction!(double)(m)?).unwrap();
|
||||
m.add_function(wrap_pyfunction!(double, m)?).unwrap();
|
||||
m.add("also_double", wrap_pyfunction!(double, m)?).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ fn r#move() -> usize {
|
|||
fn raw_ident_module(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||
use pyo3::wrap_pyfunction;
|
||||
|
||||
module.add_function(wrap_pyfunction!(r#move))
|
||||
module.add_function(wrap_pyfunction!(r#move, module)?)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -188,7 +188,7 @@ fn custom_named_fn() -> usize {
|
|||
fn foobar_module(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||
use pyo3::wrap_pyfunction;
|
||||
|
||||
m.add_function(wrap_pyfunction!(custom_named_fn))?;
|
||||
m.add_function(wrap_pyfunction!(custom_named_fn, m)?)?;
|
||||
m.dict().set_item("yay", "me")?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ fn subfunction() -> String {
|
|||
fn submodule(module: &PyModule) -> PyResult<()> {
|
||||
use pyo3::wrap_pyfunction;
|
||||
|
||||
module.add_function(wrap_pyfunction!(subfunction))?;
|
||||
module.add_function(wrap_pyfunction!(subfunction, module)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -229,7 +229,7 @@ fn submodule(module: &PyModule) -> PyResult<()> {
|
|||
fn submodule_with_init_fn(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||
use pyo3::wrap_pyfunction;
|
||||
|
||||
module.add_function(wrap_pyfunction!(subfunction))?;
|
||||
module.add_function(wrap_pyfunction!(subfunction, module)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ fn superfunction() -> String {
|
|||
fn supermodule(py: Python, module: &PyModule) -> PyResult<()> {
|
||||
use pyo3::wrap_pyfunction;
|
||||
|
||||
module.add_function(wrap_pyfunction!(superfunction))?;
|
||||
module.add_function(wrap_pyfunction!(superfunction, module)?)?;
|
||||
let module_to_add = PyModule::new(py, "submodule")?;
|
||||
submodule(module_to_add)?;
|
||||
module.add_submodule(module_to_add)?;
|
||||
|
@ -291,7 +291,7 @@ fn vararg_module(_py: Python, m: &PyModule) -> PyResult<()> {
|
|||
ext_vararg_fn(py, a, vararg)
|
||||
}
|
||||
|
||||
m.add_function(pyo3::wrap_pyfunction!(ext_vararg_fn))
|
||||
m.add_function(pyo3::wrap_pyfunction!(ext_vararg_fn, m)?)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -368,15 +368,17 @@ fn pyfunction_with_module_and_args_kwargs<'a>(
|
|||
|
||||
#[pymodule]
|
||||
fn module_with_functions_with_module(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(pyo3::wrap_pyfunction!(pyfunction_with_module))?;
|
||||
m.add_function(pyo3::wrap_pyfunction!(pyfunction_with_module_and_py))?;
|
||||
m.add_function(pyo3::wrap_pyfunction!(pyfunction_with_module_and_arg))?;
|
||||
m.add_function(pyo3::wrap_pyfunction!(pyfunction_with_module, m)?)?;
|
||||
m.add_function(pyo3::wrap_pyfunction!(pyfunction_with_module_and_py, m)?)?;
|
||||
m.add_function(pyo3::wrap_pyfunction!(pyfunction_with_module_and_arg, m)?)?;
|
||||
m.add_function(pyo3::wrap_pyfunction!(
|
||||
pyfunction_with_module_and_default_arg
|
||||
))?;
|
||||
pyfunction_with_module_and_default_arg,
|
||||
m
|
||||
)?)?;
|
||||
m.add_function(pyo3::wrap_pyfunction!(
|
||||
pyfunction_with_module_and_args_kwargs
|
||||
))
|
||||
pyfunction_with_module_and_args_kwargs,
|
||||
m
|
||||
)?)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -100,7 +100,7 @@ fn test_raw_function() {
|
|||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let raw_func = raw_pycfunction!(optional_bool);
|
||||
let fun = PyCFunction::new_with_keywords(raw_func, "fun", "", None, py).unwrap();
|
||||
let fun = PyCFunction::new_with_keywords(raw_func, "fun", "\0", py.into()).unwrap();
|
||||
let res = fun.call((), None).unwrap().extract::<&str>().unwrap();
|
||||
assert_eq!(res, "Some(true)");
|
||||
let res = fun.call((false,), None).unwrap().extract::<&str>().unwrap();
|
||||
|
@ -109,7 +109,7 @@ fn test_raw_function() {
|
|||
assert!(no_module);
|
||||
|
||||
let module = PyModule::new(py, "cool_module").unwrap();
|
||||
module.add_function(&|_| Ok(fun)).unwrap();
|
||||
module.add_function(fun).unwrap();
|
||||
let res = module
|
||||
.getattr("fun")
|
||||
.unwrap()
|
||||
|
|
Loading…
Reference in New Issue