Implement second form of py_fn!() (inline function definition)

This commit is contained in:
Daniel Grunwald 2016-03-07 23:48:44 +01:00
parent 3af6e17841
commit 9b278ba56b
3 changed files with 35 additions and 16 deletions

View File

@ -144,7 +144,7 @@ macro_rules! py_argparse {
macro_rules! py_argparse_parse_plist {
// Parses a parameter-list into a format more suitable for consumption by Rust macros.
// py_argparse_parse_plist! { callback { initial_args } (plist) }
// = callback! { initial_args [{ {**} pname:ptype = {default-value} } ...] }
// = callback! { initial_args [{ pname:ptype = [ {**} {default-value} ] } ...] }
// The braces around the *s and the default-value are used even if they are empty.
// Special-case entry-point for empty parameter list:
@ -174,7 +174,7 @@ macro_rules! py_argparse_parse_plist_impl {
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { {**} $name:$t = {} } ]
[ $($output)* { $name:$t = [ {**} {} ] } ]
($($tail)*)
}
};
@ -184,7 +184,7 @@ macro_rules! py_argparse_parse_plist_impl {
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { {**} $name:&$crate::PyDict = {} } ]
[ $($output)* { $name:&$crate::PyDict = [ {**} {} ] } ]
($($tail)*)
}
};
@ -194,7 +194,7 @@ macro_rules! py_argparse_parse_plist_impl {
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { {*} $name:$t = {} } ]
[ $($output)* { $name:$t = [ {*} {} ] } ]
($($tail)*)
}
};
@ -204,7 +204,7 @@ macro_rules! py_argparse_parse_plist_impl {
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { {*} $name:&$crate::PyTuple = {} } ]
[ $($output)* { $name:&$crate::PyTuple = [ {*} {} ] } ]
($($tail)*)
}
};
@ -214,7 +214,7 @@ macro_rules! py_argparse_parse_plist_impl {
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { {} $name:$t = {} } ]
[ $($output)* { $name:$t = [ {} {} ] } ]
($($tail)*)
}
};
@ -224,7 +224,7 @@ macro_rules! py_argparse_parse_plist_impl {
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { {} $name:&$crate::PyObject = {} } ]
[ $($output)* { $name:&$crate::PyObject = [ {} {} ] } ]
($($tail)*)
}
};
@ -234,7 +234,7 @@ macro_rules! py_argparse_parse_plist_impl {
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { {} $name:$t = {$default} } ]
[ $($output)* { $name:$t = [ {} {$default} ] } ]
($($tail)*)
}
};
@ -246,11 +246,11 @@ macro_rules! py_argparse_parse_plist_impl {
#[doc(hidden)]
macro_rules! py_argparse_impl {
($py:expr, $fname:expr, $args:expr, $kwargs:expr, $body:block,
[ $( { $stars:tt $pname:ident : $ptype:ty = $default:tt } )* ]
[ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]
) => {{
const PARAMS: &'static [$crate::argparse::ParamDescription<'static>] = &[
$(
py_argparse_param_description! { $stars $pname : $ptype = $default }
py_argparse_param_description! { $pname : $ptype = $detail }
),*
];
let py: $crate::Python = $py;
@ -265,7 +265,7 @@ macro_rules! py_argparse_impl {
// (at least until we can use ? + catch, assuming that will be hygienic wrt. macros),
// so use a recursive helper macro for that:
py_argparse_extract!( py, _iter, $body,
[ $( { $stars $pname : $ptype = $default } )* ])
[ $( { $pname : $ptype = $detail } )* ])
},
Err(e) => Err(e)
}
@ -300,7 +300,7 @@ pub unsafe fn get_kwargs(py: Python, ptr: *mut ffi::PyObject) -> Option<PyDict>
#[doc(hidden)]
macro_rules! py_argparse_param_description {
// normal parameter
{ {} $pname:ident : $ptype:ty = {} } => (
{ $pname:ident : $ptype:ty = [ {} {} ] } => (
$crate::argparse::ParamDescription {
name: stringify!($pname),
is_optional: false
@ -315,7 +315,7 @@ macro_rules! py_argparse_extract {
( $py:expr, $iter:expr, $body:block, [] ) => { $body };
// normal parameter
( $py:expr, $iter:expr, $body:block,
[ { {} $pname:ident : $ptype:ty = {} } $($tail:tt)* ]
[ { $pname:ident : $ptype:ty = [ {} {} ] } $($tail:tt)* ]
) => {
// First unwrap() asserts the iterated sequence is long enough (which should be guaranteed);
// second unwrap() asserts the parameter was not missing (which fn parse_args already checked for).

View File

@ -97,7 +97,7 @@ macro_rules! py_fn {
($py:expr, $f:ident $plist:tt ) => {
py_argparse_parse_plist! { py_fn_impl { $py, $f } $plist }
};
($py:expr, $f:ident $plist:tt -> $ret:ty { $($body:tt)* } ) => {
($py:ident, $f:ident $plist:tt -> $ret:ty { $($body:tt)* } ) => {
py_argparse_parse_plist! { py_fn_impl { $py, $f, $ret, { $($body)* } } $plist }
};
}
@ -105,7 +105,8 @@ macro_rules! py_fn {
#[macro_export]
#[doc(hidden)]
macro_rules! py_fn_impl {
{ $py:expr, $f:ident [ $( { $stars:tt $pname:ident : $ptype:ty = $default:tt } )* ] } => {{
// Form 1: reference existing function
{ $py:expr, $f:ident [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ] } => {{
// <DUMMY> is workaround for rust issue #26201
unsafe extern "C" fn wrap<DUMMY>(
_slf: *mut $crate::_detail::ffi::PyObject,
@ -117,7 +118,7 @@ macro_rules! py_fn_impl {
stringify!($f),
|py| {
py_argparse_raw!(py, Some(stringify!($f)), args, kwargs,
[ $( { $stars $pname : $ptype= $default } )* ]
[ $( { $pname : $ptype= $detail } )* ]
{
$f(py $(, $pname )* )
})
@ -128,6 +129,11 @@ macro_rules! py_fn_impl {
py_method_def!(stringify!($f), 0, wrap::<()>))
}
}};
// Form 2: inline function definition
{ $py:ident, $f:ident, $ret:ty, $body:block [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ] } => {{
fn $f($py: $crate::Python $( , $pname : $ptype )* ) -> $ret $body
py_fn_impl!($py, $f [ $( { $pname : $ptype = $detail } )* ])
}}
}
pub unsafe fn handle_callback<F, T>(_location: &str, f: F) -> *mut ffi::PyObject

View File

@ -52,6 +52,19 @@ fn one_arg() {
assert!(obj.call(py, NoArgs, Some(&dict)).is_err());
}
#[test]
fn inline_two_args() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj = py_fn!(py, f(a: i32, b: i32) -> PyResult<i32> {
drop(py); // avoid unused variable warning
Ok(a * b)
});
assert!(obj.call(py, NoArgs, None).is_err());
assert_eq!(obj.call(py, (6, 7), None).unwrap().extract::<i32>(py).unwrap(), 42);
}
/* TODO: reimplement flexible sig support
#[test]
fn flexible_sig() {