Add parameter extraction support to py_fn!
and py_method!
.
These macros now support specifying an argument list: `py_fn!(myfn(myarg: i32))` will expect `myfn` to be a function with the signature: `fn myfn<'p>(py: Python<'p>, myarg: i32) -> PyResult<'p, _>` It can called from python as `myfn(1)` or using keyword arguments: `myfn(myarg=1)`. If no parameter list is specified (`py_fn!(myfn)`), the expected signature now includes the keyword arguments: `fn run<'p>(py: Python<'p>, args: &PyTuple<'p>, kwargs: Option<&PyDict<'p>>)` Due to the additional `kwargs` argument, this is a [breaking-change].
This commit is contained in:
parent
072f4d24eb
commit
a23b5b5910
|
@ -4,18 +4,18 @@
|
|||
|
||||
#[macro_use] extern crate cpython;
|
||||
|
||||
use cpython::{PythonObject, PyObject, PyRustObject, PyTuple, PyResult};
|
||||
use cpython::{PythonObject, PyObject, PyRustObject, PyResult};
|
||||
|
||||
py_module_initializer!(custom_type, |_py, m| {
|
||||
try!(m.add("__doc__", "Module documentation string"));
|
||||
try!(m.add_type::<i32>("MyType")
|
||||
.add("a", py_method!(a))
|
||||
.add("a", py_method!(a()))
|
||||
.finish());
|
||||
Ok(())
|
||||
});
|
||||
|
||||
fn a<'p>(slf: &PyRustObject<'p, i32>, args: &PyTuple<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
println!("a() was called with self={:?} and args={:?}", slf.get(), args.as_object());
|
||||
fn a<'p>(slf: &PyRustObject<'p, i32>) -> PyResult<'p, PyObject<'p>> {
|
||||
println!("a() was called with self={:?}", slf.get());
|
||||
Ok(slf.python().None())
|
||||
}
|
||||
|
||||
|
|
|
@ -4,24 +4,29 @@
|
|||
|
||||
#[macro_use] extern crate cpython;
|
||||
|
||||
use cpython::{PyObject, PyResult,Python, PyTuple};
|
||||
use cpython::{PyObject, PyResult, Python, PyTuple, PyDict};
|
||||
|
||||
py_module_initializer!(hello, |_py, m| {
|
||||
try!(m.add("__doc__", "Module documentation string"));
|
||||
try!(m.add("run", py_fn!(run)));
|
||||
try!(m.add("val", py_fn!(val)));
|
||||
try!(m.add("val", py_fn!(val())));
|
||||
Ok(())
|
||||
});
|
||||
|
||||
fn run<'p>(py: Python<'p>, args: &PyTuple<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
fn run<'p>(py: Python<'p>, args: &PyTuple<'p>, kwargs: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>> {
|
||||
println!("Rust says: Hello Python!");
|
||||
for arg in args {
|
||||
println!("Rust got {}", arg);
|
||||
}
|
||||
if let Some(kwargs) = kwargs {
|
||||
for (key, val) in kwargs.items() {
|
||||
println!("{} = {}", key, val);
|
||||
}
|
||||
}
|
||||
Ok(py.None())
|
||||
}
|
||||
|
||||
fn val<'p>(_: Python<'p>, _: &PyTuple<'p>) -> PyResult<'p, i32> {
|
||||
fn val<'p>(_: Python<'p>) -> PyResult<'p, i32> {
|
||||
Ok(42)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
//! This module contains logic for parsing a python argument list.
|
||||
//! See also the macros `py_argparse!`, `py_fn` and `py_method`.
|
||||
|
||||
use std::ptr;
|
||||
use python::{Python, PythonObject};
|
||||
|
@ -25,19 +26,22 @@ use conversion::ToPyObject;
|
|||
use ffi;
|
||||
use err::{self, PyResult};
|
||||
|
||||
/// Description of a python parameter; used for `parse_args()`.
|
||||
pub struct ParamDescription<'a> {
|
||||
name: &'a str,
|
||||
is_optional: bool
|
||||
/// The name of the parameter.
|
||||
pub name: &'a str,
|
||||
/// Whether the parameter is optional.
|
||||
pub is_optional: bool
|
||||
}
|
||||
|
||||
/// Parse argument list
|
||||
///
|
||||
/// fname: Name of the current function
|
||||
/// params: Declared parameters of the function
|
||||
/// args: Positional arguments
|
||||
/// kwargs: Keyword arguments
|
||||
/// output: Output array that receives the arguments.
|
||||
/// Must have same length as `params` and must be initialized to `None`.
|
||||
/// * fname: Name of the current function
|
||||
/// * params: Declared parameters of the function
|
||||
/// * args: Positional arguments
|
||||
/// * kwargs: Keyword arguments
|
||||
/// * output: Output array that receives the arguments.
|
||||
/// Must have same length as `params` and must be initialized to `None`.
|
||||
pub fn parse_args<'p>(
|
||||
fname: Option<&str>, params: &[ParamDescription],
|
||||
args: &PyTuple<'p>, kwargs: Option<&PyDict<'p>>,
|
||||
|
@ -99,10 +103,12 @@ pub fn parse_args<'p>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
macro_rules! argparse_extract {
|
||||
( ( ) $body:block ) => { $body };
|
||||
( ( $pname:ident : $ptype:ty ) $body:block) => {
|
||||
match <$ptype as $crate::ExtractPyObject>::prepare_extract($pname.as_ref().unwrap()) {
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! py_argparse_extract {
|
||||
( $iter:expr, ( ) $body:block ) => { $body };
|
||||
( $iter:expr, ( $pname:ident : $ptype:ty ) $body:block) => {
|
||||
match <$ptype as $crate::ExtractPyObject>::prepare_extract($iter.next().unwrap().as_ref().unwrap()) {
|
||||
Ok(prepared) => {
|
||||
match <$ptype as $crate::ExtractPyObject>::extract(&prepared) {
|
||||
Ok($pname) => $body,
|
||||
|
@ -112,18 +118,37 @@ macro_rules! argparse_extract {
|
|||
Err(e) => Err(e)
|
||||
}
|
||||
};
|
||||
( ( $pname:ident : $ptype:ty , $($r:tt)+ ) $body:block) => {
|
||||
argparse_extract!(($pname: $ptype) {
|
||||
argparse_extract!( ( $($r)* ) $body)
|
||||
( $iter:expr, ( $pname:ident : $ptype:ty , $($r:tt)+ ) $body:block) => {
|
||||
py_argparse_extract!($iter, ($pname: $ptype) {
|
||||
py_argparse_extract!( $iter, ( $($r)* ) $body)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! argparse_snd {
|
||||
( $fst:expr, $snd:expr) => { $snd }
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! py_argparse_snd {
|
||||
( $fst:expr, $snd:expr ) => { $snd }
|
||||
}
|
||||
|
||||
macro_rules! argparse {
|
||||
/// This macro is used to parse a parameter list into a set of variables.
|
||||
///
|
||||
/// Syntax: `py_argparse!(fname, args, kwargs, (parameter-list) { body })`
|
||||
///
|
||||
/// * `fname`: expression of type `Option<&str>`: Name of the function used in error messages.
|
||||
/// * `args`: expression of type `&PyTuple`: The position arguments
|
||||
/// * `kwargs`: expression of type `Option<&PyDict>`: The named arguments
|
||||
/// * `parameter-list`: a comma-separated list of Rust parameter declarations (`name: type`).
|
||||
/// The types used must implement the `ExtractPyObject` trait.
|
||||
/// * `body`: expression of type `PyResult<_>`.
|
||||
///
|
||||
/// `py_argparse!()` expands to code that extracts values from `args` and `kwargs` and assigns
|
||||
/// them to the parameters. If the extraction is successful, `py_argparse!()` evaluates
|
||||
/// the body expression (where the extracted parameters are available) and returns the result
|
||||
/// value of the body expression.
|
||||
/// If extraction fails, `py_argparse!()` returns a failed `PyResult` without evaluating `body`.
|
||||
#[macro_export]
|
||||
macro_rules! py_argparse {
|
||||
($fname:expr, $args:expr, $kwargs:expr, ($( $pname:ident : $ptype:ty ),*) $body:block) => {{
|
||||
const PARAMS: &'static [$crate::argparse::ParamDescription<'static>] = &[
|
||||
$(
|
||||
|
@ -133,11 +158,15 @@ macro_rules! argparse {
|
|||
}
|
||||
),*
|
||||
];
|
||||
let mut output = [$( argparse_snd!($pname, None) ),*];
|
||||
let mut output = [$( py_argparse_snd!($pname, None) ),*];
|
||||
match $crate::argparse::parse_args($fname, PARAMS, $args, $kwargs, &mut output) {
|
||||
Ok(()) => {
|
||||
let &[$(ref $pname),*] = &output;
|
||||
argparse_extract!( ( $( $pname : $ptype ),* ) $body )
|
||||
// We can't use experimental slice pattern syntax in macros
|
||||
//let &[$(ref $pname),*] = &output;
|
||||
let mut iter = output.iter();
|
||||
let ret = py_argparse_extract!( iter, ( $( $pname : $ptype ),* ) $body );
|
||||
assert!(iter.next() == None);
|
||||
ret
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
|
@ -155,7 +184,7 @@ mod test {
|
|||
let py = gil_guard.python();
|
||||
let mut called = false;
|
||||
let tuple = ("abc", 42).to_py_object(py);
|
||||
argparse!(None, &tuple, None, (x: &str, y: i32) {
|
||||
py_argparse!(None, &tuple, None, (x: &str, y: i32) {
|
||||
assert_eq!(x, "abc");
|
||||
assert_eq!(y, 42);
|
||||
called = true;
|
||||
|
|
|
@ -74,7 +74,7 @@ pub trait ToPyObject<'p> {
|
|||
///
|
||||
/// Usage:
|
||||
/// ```let obj: PyObject = ...;
|
||||
/// let prepared = <TargetType as FromPyObject>::prepare_extract(&obj);
|
||||
/// let prepared = <TargetType as ExtractPyObject>::prepare_extract(&obj);
|
||||
/// let extracted = try!(extract(&prepared));```
|
||||
///
|
||||
/// Note: depending on the implementation, the lifetime of the extracted result may
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use std::ptr;
|
||||
use python::Python;
|
||||
use objects::PyObject;
|
||||
use python::{Python, PythonObject};
|
||||
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
|
||||
use conversion::ToPyObject;
|
||||
use ffi;
|
||||
use err;
|
||||
use err::{self, PyResult};
|
||||
|
||||
/// Creates a Python callable object that invokes a Rust function.
|
||||
///
|
||||
|
@ -37,14 +37,19 @@ macro_rules! py_fn {
|
|||
($f: ident) => ( interpolate_idents! {{
|
||||
unsafe extern "C" fn [ wrap_ $f ](
|
||||
_slf: *mut $crate::_detail::ffi::PyObject,
|
||||
args: *mut $crate::_detail::ffi::PyObject)
|
||||
args: *mut $crate::_detail::ffi::PyObject,
|
||||
kwargs: *mut $crate::_detail::ffi::PyObject)
|
||||
-> *mut $crate::_detail::ffi::PyObject
|
||||
{
|
||||
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_fn!");
|
||||
let py = $crate::_detail::bounded_assume_gil_acquired(&args);
|
||||
let args = $crate::PyObject::from_borrowed_ptr(py, args);
|
||||
let args = <$crate::PyTuple as $crate::PythonObject>::unchecked_downcast_from(args);
|
||||
match $f(py, &args) {
|
||||
let kwargs = match $crate::PyObject::from_borrowed_ptr_opt(py, kwargs) {
|
||||
Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)),
|
||||
None => None
|
||||
};
|
||||
match $f(py, &args, kwargs.as_ref()) {
|
||||
Ok(val) => {
|
||||
let obj = $crate::ToPyObject::into_py_object(val, py);
|
||||
return $crate::PythonObject::into_object(obj).steal_ptr();
|
||||
|
@ -58,20 +63,68 @@ macro_rules! py_fn {
|
|||
static mut [ method_def_ $f ]: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
|
||||
//ml_name: bytes!(stringify!($f), "\0"),
|
||||
ml_name: 0 as *const $crate::_detail::libc::c_char,
|
||||
ml_meth: Some([ wrap_ $f ]),
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS,
|
||||
ml_meth: None,
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS | $crate::_detail::ffi::METH_KEYWORDS,
|
||||
ml_doc: 0 as *const $crate::_detail::libc::c_char
|
||||
};
|
||||
unsafe {
|
||||
[ method_def_ $f ].ml_name =
|
||||
concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
[ method_def_ $f ].ml_name = concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
[ method_def_ $f ].ml_meth = Some(
|
||||
std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
|
||||
$crate::_detail::ffi::PyCFunction>([ wrap_ $f ])
|
||||
);
|
||||
$crate::_detail::py_fn_impl(&mut [ method_def_ $f ])
|
||||
}
|
||||
}})
|
||||
}});
|
||||
($f: ident ( $( $pname:ident : $ptype:ty ),* ) ) => ( interpolate_idents! {{
|
||||
unsafe extern "C" fn [ wrap_ $f ](
|
||||
_slf: *mut $crate::_detail::ffi::PyObject,
|
||||
args: *mut $crate::_detail::ffi::PyObject,
|
||||
kwargs: *mut $crate::_detail::ffi::PyObject)
|
||||
-> *mut $crate::_detail::ffi::PyObject
|
||||
{
|
||||
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_fn!");
|
||||
let py = $crate::_detail::bounded_assume_gil_acquired(&args);
|
||||
let args = $crate::PyObject::from_borrowed_ptr(py, args);
|
||||
let args = <$crate::PyTuple as $crate::PythonObject>::unchecked_downcast_from(args);
|
||||
let kwargs = match $crate::PyObject::from_borrowed_ptr_opt(py, kwargs) {
|
||||
Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)),
|
||||
None => None
|
||||
};
|
||||
match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(),
|
||||
( $($pname : $ptype),* ) { $f( py, $($pname),* ) })
|
||||
{
|
||||
Ok(val) => {
|
||||
let obj = $crate::ToPyObject::into_py_object(val, py);
|
||||
return $crate::PythonObject::into_object(obj).steal_ptr();
|
||||
}
|
||||
Err(e) => {
|
||||
e.restore();
|
||||
return ::std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
static mut [ method_def_ $f ]: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
|
||||
//ml_name: bytes!(stringify!($f), "\0"),
|
||||
ml_name: 0 as *const $crate::_detail::libc::c_char,
|
||||
ml_meth: None,
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS | $crate::_detail::ffi::METH_KEYWORDS,
|
||||
ml_doc: 0 as *const $crate::_detail::libc::c_char
|
||||
};
|
||||
unsafe {
|
||||
[ method_def_ $f ].ml_name = concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
[ method_def_ $f ].ml_meth = Some(
|
||||
std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
|
||||
$crate::_detail::ffi::PyCFunction>([ wrap_ $f ])
|
||||
);
|
||||
$crate::_detail::py_fn_impl(&mut [ method_def_ $f ])
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
pub struct PyFn(*mut ffi::PyMethodDef);
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn py_fn_impl(def: *mut ffi::PyMethodDef) -> PyFn {
|
||||
PyFn(def)
|
||||
}
|
||||
|
@ -86,3 +139,4 @@ impl <'p> ToPyObject<'p> for PyFn {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ mod conversion;
|
|||
mod objects;
|
||||
mod objectprotocol;
|
||||
mod pythonrun;
|
||||
pub mod argparse;
|
||||
mod function;
|
||||
mod rustobject;
|
||||
|
||||
|
@ -168,15 +169,15 @@ pub mod _detail {
|
|||
/// #![feature(plugin)]
|
||||
/// #![plugin(interpolate_idents)]
|
||||
/// #[macro_use] extern crate cpython;
|
||||
/// use cpython::{Python, PyResult, PyObject, PyTuple};
|
||||
/// use cpython::{Python, PyResult, PyObject};
|
||||
///
|
||||
/// py_module_initializer!(example, |py, m| {
|
||||
/// try!(m.add("__doc__", "Module documentation string"));
|
||||
/// try!(m.add("run", py_fn!(run)));
|
||||
/// try!(m.add("run", py_fn!(run())));
|
||||
/// Ok(())
|
||||
/// });
|
||||
///
|
||||
/// fn run<'p>(py: Python<'p>, args: &PyTuple<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
/// fn run<'p>(py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
/// println!("Rust says: Hello Python!");
|
||||
/// Ok(py.None())
|
||||
/// }
|
||||
|
|
|
@ -41,9 +41,9 @@ use err;
|
|||
/// PyTuple, PyRustObject, PyRustTypeBuilder};
|
||||
/// use cpython::{exc};
|
||||
///
|
||||
/// fn mul<'p>(slf: &PyRustObject<'p, i32>, args: &PyTuple<'p>) -> PyResult<'p, i32> {
|
||||
/// fn mul<'p>(slf: &PyRustObject<'p, i32>, arg: i32) -> PyResult<'p, i32> {
|
||||
/// let py = slf.python();
|
||||
/// match slf.get().checked_mul(try!(args.get_item(0).extract::<i32>())) {
|
||||
/// match slf.get().checked_mul(arg) {
|
||||
/// Some(val) => Ok(val),
|
||||
/// None => Err(PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None))
|
||||
/// }
|
||||
|
@ -52,7 +52,7 @@ use err;
|
|||
/// fn main() {
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let multiplier_type = PyRustTypeBuilder::<i32>::new(gil.python(), "Multiplier")
|
||||
/// .add("mul", py_method!(mul))
|
||||
/// .add("mul", py_method!(mul(arg: i32)))
|
||||
/// .finish().unwrap();
|
||||
/// let obj = multiplier_type.create_instance(3, ()).into_object();
|
||||
/// let result = obj.call_method("mul", &(4,), None).unwrap().extract::<i32>().unwrap();
|
||||
|
@ -64,7 +64,8 @@ macro_rules! py_method {
|
|||
($f: ident) => ( interpolate_idents! {{
|
||||
unsafe extern "C" fn [ wrap_ $f ](
|
||||
slf: *mut $crate::_detail::ffi::PyObject,
|
||||
args: *mut $crate::_detail::ffi::PyObject)
|
||||
args: *mut $crate::_detail::ffi::PyObject,
|
||||
kwargs: *mut $crate::_detail::ffi::PyObject)
|
||||
-> *mut $crate::_detail::ffi::PyObject
|
||||
{
|
||||
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_method!");
|
||||
|
@ -73,7 +74,11 @@ macro_rules! py_method {
|
|||
let slf = $crate::PythonObject::unchecked_downcast_from(slf);
|
||||
let args = $crate::PyObject::from_borrowed_ptr(py, args);
|
||||
let args = <$crate::PyTuple as $crate::PythonObject>::unchecked_downcast_from(args);
|
||||
match $f(&slf, &args) {
|
||||
let kwargs = match $crate::PyObject::from_borrowed_ptr_opt(py, kwargs) {
|
||||
Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)),
|
||||
None => None
|
||||
};
|
||||
match $f(&slf, &args, kwargs.as_ref()) {
|
||||
Ok(val) => {
|
||||
let obj = $crate::ToPyObject::into_py_object(val, py);
|
||||
return $crate::PythonObject::into_object(obj).steal_ptr();
|
||||
|
@ -87,27 +92,134 @@ macro_rules! py_method {
|
|||
static mut [ method_def_ $f ]: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
|
||||
//ml_name: bytes!(stringify!($f), "\0"),
|
||||
ml_name: 0 as *const $crate::_detail::libc::c_char,
|
||||
ml_meth: Some([ wrap_ $f ]),
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS,
|
||||
ml_meth: None,
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS | $crate::_detail::ffi::METH_KEYWORDS,
|
||||
ml_doc: 0 as *const $crate::_detail::libc::c_char
|
||||
};
|
||||
unsafe {
|
||||
[ method_def_ $f ].ml_name =
|
||||
concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
$crate::_detail::py_method_impl(&mut [ method_def_ $f ], $f)
|
||||
[ method_def_ $f ].ml_name = concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
[ method_def_ $f ].ml_meth = Some(
|
||||
std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
|
||||
$crate::_detail::ffi::PyCFunction>([ wrap_ $f ])
|
||||
);
|
||||
$crate::_detail::py_method_impl::py_method_impl(&mut [ method_def_ $f ], $f)
|
||||
}
|
||||
}});
|
||||
($f: ident ( $( $pname:ident : $ptype:ty ),* ) ) => ( interpolate_idents! {{
|
||||
unsafe extern "C" fn [ wrap_ $f ](
|
||||
slf: *mut $crate::_detail::ffi::PyObject,
|
||||
args: *mut $crate::_detail::ffi::PyObject,
|
||||
kwargs: *mut $crate::_detail::ffi::PyObject)
|
||||
-> *mut $crate::_detail::ffi::PyObject
|
||||
{
|
||||
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_method!");
|
||||
let py = $crate::_detail::bounded_assume_gil_acquired(&args);
|
||||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf);
|
||||
let slf = $crate::PythonObject::unchecked_downcast_from(slf);
|
||||
let args = $crate::PyObject::from_borrowed_ptr(py, args);
|
||||
let args = <$crate::PyTuple as $crate::PythonObject>::unchecked_downcast_from(args);
|
||||
let kwargs = match $crate::PyObject::from_borrowed_ptr_opt(py, kwargs) {
|
||||
Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)),
|
||||
None => None
|
||||
};
|
||||
match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(),
|
||||
( $($pname : $ptype),* ) { $f( &slf, $($pname),* ) })
|
||||
{
|
||||
Ok(val) => {
|
||||
let obj = $crate::ToPyObject::into_py_object(val, py);
|
||||
return $crate::PythonObject::into_object(obj).steal_ptr();
|
||||
}
|
||||
Err(e) => {
|
||||
e.restore();
|
||||
return ::std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
static mut [ method_def_ $f ]: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
|
||||
//ml_name: bytes!(stringify!($f), "\0"),
|
||||
ml_name: 0 as *const $crate::_detail::libc::c_char,
|
||||
ml_meth: None,
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS | $crate::_detail::ffi::METH_KEYWORDS,
|
||||
ml_doc: 0 as *const $crate::_detail::libc::c_char
|
||||
};
|
||||
unsafe {
|
||||
[ method_def_ $f ].ml_name = concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
[ method_def_ $f ].ml_meth = Some(
|
||||
std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
|
||||
$crate::_detail::ffi::PyCFunction>([ wrap_ $f ])
|
||||
);
|
||||
py_method_call_impl!(&mut [ method_def_ $f ], $f ( $($pname : $ptype),* ) )
|
||||
}
|
||||
}})
|
||||
}
|
||||
|
||||
pub struct MethodDescriptor<T>(*mut ffi::PyMethodDef, marker::PhantomData<fn(&T)>);
|
||||
|
||||
// py_method_impl takes fn(&T) to ensure that the T in MethodDescriptor<T>
|
||||
// corresponds to the T in the function signature.
|
||||
pub unsafe fn py_method_impl<'p, T, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&T, &PyTuple<'p>) -> err::PyResult<'p, R>
|
||||
) -> MethodDescriptor<T> {
|
||||
MethodDescriptor(def, marker::PhantomData)
|
||||
#[doc(hidden)]
|
||||
pub mod py_method_impl {
|
||||
use ffi;
|
||||
use err;
|
||||
use objects::{PyTuple, PyDict};
|
||||
use super::MethodDescriptor;
|
||||
use std::marker;
|
||||
|
||||
// py_method_impl takes fn(&T) to ensure that the T in MethodDescriptor<T>
|
||||
// corresponds to the T in the function signature.
|
||||
pub unsafe fn py_method_impl<'p, T, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&T, &PyTuple<'p>, Option<&PyDict<'p>>) -> err::PyResult<'p, R>
|
||||
) -> MethodDescriptor<T> {
|
||||
MethodDescriptor(def, marker::PhantomData)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! py_method_call_impl {
|
||||
( $def:expr, $f:ident ( ) )
|
||||
=> { $crate::_detail::py_method_impl::py_method_impl_0($def, $f) };
|
||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty ) )
|
||||
=> { $crate::_detail::py_method_impl::py_method_impl_1($def, $f) };
|
||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty ) )
|
||||
=> { $crate::_detail::py_method_impl::py_method_impl_2($def, $f) };
|
||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty ) )
|
||||
=> { $crate::_detail::py_method_impl::py_method_impl_3($def, $f) };
|
||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty, $n4:ident : $t4:ty ) )
|
||||
=> { $crate::_detail::py_method_impl::py_method_impl_3($def, $f) };
|
||||
}
|
||||
|
||||
pub unsafe fn py_method_impl_0<'p, T, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&T) -> err::PyResult<'p, R>
|
||||
) -> MethodDescriptor<T> {
|
||||
MethodDescriptor(def, marker::PhantomData)
|
||||
}
|
||||
|
||||
pub unsafe fn py_method_impl_1<'p, T, P1, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&T, P1) -> err::PyResult<'p, R>
|
||||
) -> MethodDescriptor<T> {
|
||||
MethodDescriptor(def, marker::PhantomData)
|
||||
}
|
||||
|
||||
pub unsafe fn py_method_impl_2<'p, T, P1, P2, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&T, P1, P2) -> err::PyResult<'p, R>
|
||||
) -> MethodDescriptor<T> {
|
||||
MethodDescriptor(def, marker::PhantomData)
|
||||
}
|
||||
|
||||
pub unsafe fn py_method_impl_3<'p, T, P1, P2, P3, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&T, P1, P2, P3) -> err::PyResult<'p, R>
|
||||
) -> MethodDescriptor<T> {
|
||||
MethodDescriptor(def, marker::PhantomData)
|
||||
}
|
||||
|
||||
pub unsafe fn py_method_impl_4<'p, T, P1, P2, P3, P4, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&T, P1, P2, P3, P4) -> err::PyResult<'p, R>
|
||||
) -> MethodDescriptor<T> {
|
||||
MethodDescriptor(def, marker::PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl <'p, T> TypeMember<'p, T> for MethodDescriptor<T> where T: PythonObject<'p> {
|
||||
|
@ -144,16 +256,16 @@ impl <'p, T> TypeMember<'p, T> for MethodDescriptor<T> where T: PythonObject<'p>
|
|||
/// PyTuple, PyType, PyRustTypeBuilder, NoArgs};
|
||||
/// use cpython::{exc};
|
||||
///
|
||||
/// fn method<'p>(ty: &PyType<'p>, args: &PyTuple<'p>) -> PyResult<'p, i32> {
|
||||
/// fn method<'p>(py: Python<'p>) -> PyResult<'p, i32> {
|
||||
/// Ok(42)
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let gil = Python::acquire_gil();
|
||||
/// let my_type = PyRustTypeBuilder::<i32>::new(gil.python(), "MyType")
|
||||
/// .add("method", py_class_method!(method))
|
||||
/// .add("method", py_class_method!(method()))
|
||||
/// .finish().unwrap();
|
||||
/// let result = my_type.as_object().call_method("method", &NoArgs, None).unwrap();
|
||||
/// let result = my_type.as_object().call_method("method", NoArgs, None).unwrap();
|
||||
/// assert_eq!(42, result.extract::<i32>().unwrap());
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -162,7 +274,8 @@ macro_rules! py_class_method {
|
|||
($f: ident) => ( interpolate_idents! {{
|
||||
unsafe extern "C" fn [ wrap_ $f ](
|
||||
slf: *mut $crate::_detail::ffi::PyObject,
|
||||
args: *mut $crate::_detail::ffi::PyObject)
|
||||
args: *mut $crate::_detail::ffi::PyObject,
|
||||
kwargs: *mut $crate::_detail::ffi::PyObject)
|
||||
-> *mut $crate::_detail::ffi::PyObject
|
||||
{
|
||||
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_method!");
|
||||
|
@ -171,7 +284,11 @@ macro_rules! py_class_method {
|
|||
let slf = <$crate::PyType as $crate::PythonObject>::unchecked_downcast_from(slf);
|
||||
let args = $crate::PyObject::from_borrowed_ptr(py, args);
|
||||
let args = <$crate::PyTuple as $crate::PythonObject>::unchecked_downcast_from(args);
|
||||
match $f(&slf, &args) {
|
||||
let kwargs = match $crate::PyObject::from_borrowed_ptr_opt(py, kwargs) {
|
||||
Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)),
|
||||
None => None
|
||||
};
|
||||
match $f(&slf, &args, kwargs.as_ref()) {
|
||||
Ok(val) => {
|
||||
let obj = $crate::ToPyObject::into_py_object(val, py);
|
||||
return $crate::PythonObject::into_object(obj).steal_ptr();
|
||||
|
@ -184,24 +301,76 @@ macro_rules! py_class_method {
|
|||
}
|
||||
static mut [ method_def_ $f ]: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
|
||||
//ml_name: bytes!(stringify!($f), "\0"),
|
||||
ml_name: b"<rust method>\0" as *const u8 as *const $crate::_detail::libc::c_char,
|
||||
ml_meth: Some([ wrap_ $f ]),
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS | $crate::_detail::ffi::METH_CLASS,
|
||||
ml_name: 0 as *const $crate::_detail::libc::c_char,
|
||||
ml_meth: None,
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS
|
||||
| $crate::_detail::ffi::METH_KEYWORDS
|
||||
| $crate::_detail::ffi::METH_CLASS,
|
||||
ml_doc: 0 as *const $crate::_detail::libc::c_char
|
||||
};
|
||||
unsafe { $crate::_detail::py_class_method_impl(&mut [ method_def_ $f ], $f) }
|
||||
unsafe {
|
||||
[ method_def_ $f ].ml_name = concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
[ method_def_ $f ].ml_meth = Some(
|
||||
std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
|
||||
$crate::_detail::ffi::PyCFunction>([ wrap_ $f ])
|
||||
);
|
||||
$crate::_detail::py_class_method_impl(&mut [ method_def_ $f ])
|
||||
}
|
||||
}});
|
||||
($f: ident ( $( $pname:ident : $ptype:ty ),* ) ) => ( interpolate_idents! {{
|
||||
unsafe extern "C" fn [ wrap_ $f ](
|
||||
slf: *mut $crate::_detail::ffi::PyObject,
|
||||
args: *mut $crate::_detail::ffi::PyObject,
|
||||
kwargs: *mut $crate::_detail::ffi::PyObject)
|
||||
-> *mut $crate::_detail::ffi::PyObject
|
||||
{
|
||||
let _guard = $crate::_detail::PanicGuard::with_message("Rust panic in py_method!");
|
||||
let py = $crate::_detail::bounded_assume_gil_acquired(&args);
|
||||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf);
|
||||
let slf = <$crate::PyType as $crate::PythonObject>::unchecked_downcast_from(slf);
|
||||
let args = $crate::PyObject::from_borrowed_ptr(py, args);
|
||||
let args = <$crate::PyTuple as $crate::PythonObject>::unchecked_downcast_from(args);
|
||||
let kwargs = match $crate::PyObject::from_borrowed_ptr_opt(py, kwargs) {
|
||||
Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)),
|
||||
None => None
|
||||
};
|
||||
match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(),
|
||||
( $($pname : $ptype),* ) { $f( py, $($pname),* ) })
|
||||
{
|
||||
Ok(val) => {
|
||||
let obj = $crate::ToPyObject::into_py_object(val, py);
|
||||
return $crate::PythonObject::into_object(obj).steal_ptr();
|
||||
}
|
||||
Err(e) => {
|
||||
e.restore();
|
||||
return ::std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
static mut [ method_def_ $f ]: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
|
||||
//ml_name: bytes!(stringify!($f), "\0"),
|
||||
ml_name: 0 as *const $crate::_detail::libc::c_char,
|
||||
ml_meth: None,
|
||||
ml_flags: $crate::_detail::ffi::METH_VARARGS
|
||||
| $crate::_detail::ffi::METH_KEYWORDS
|
||||
| $crate::_detail::ffi::METH_CLASS,
|
||||
ml_doc: 0 as *const $crate::_detail::libc::c_char
|
||||
};
|
||||
unsafe {
|
||||
[ method_def_ $f ].ml_name = concat!(stringify!($f), "\0").as_ptr() as *const _;
|
||||
[ method_def_ $f ].ml_meth = Some(
|
||||
std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
|
||||
$crate::_detail::ffi::PyCFunction>([ wrap_ $f ])
|
||||
);
|
||||
$crate::_detail::py_class_method_impl(&mut [ method_def_ $f ])
|
||||
}
|
||||
}})
|
||||
}
|
||||
|
||||
pub struct ClassMethodDescriptor(*mut ffi::PyMethodDef);
|
||||
|
||||
// py_method_impl takes fn(&T) to ensure that the T in MethodDescriptor<T>
|
||||
// corresponds to the T in the function signature.
|
||||
pub unsafe fn py_class_method_impl<'p, R>(
|
||||
def: *mut ffi::PyMethodDef,
|
||||
_f: fn(&PyType<'p>, &PyTuple<'p>) -> err::PyResult<'p, R>
|
||||
) -> ClassMethodDescriptor
|
||||
{
|
||||
#[inline]
|
||||
pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDescriptor {
|
||||
ClassMethodDescriptor(def)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue