Implement optional parameters for reference types

This commit is contained in:
Luthaf 2017-01-26 21:35:16 +01:00
parent 9707c5ab72
commit d615c319f6
2 changed files with 35 additions and 12 deletions

View file

@ -258,8 +258,17 @@ macro_rules! py_argparse_parse_plist_impl {
($($tail)*)
}
};
// Optional parameter with reference extraction
{ $callback:ident $initial_args:tt [ $($output:tt)* ]
( $name:ident : &$t:ty = $default:expr, $($tail:tt)* )
} => {
py_argparse_parse_plist_impl! {
$callback $initial_args
[ $($output)* { $name:&$t = [ {} {$default} {$t} ] } ]
($($tail)*)
}
};
// Optional parameter
// TODO: with reference extraction?
{ $callback:ident $initial_args:tt [ $($output:tt)* ]
( $name:ident : $t:ty = $default:expr , $($tail:tt)* )
} => {
@ -353,8 +362,8 @@ macro_rules! py_argparse_param_description {
is_optional: false
}
);
// optional parameter with a default value
{ $pname:ident : $ptype:ty = [ {} {$default:expr} {} ] } => (
// optional parameters
{ $pname:ident : $ptype:ty = [ {} {$default:expr} {$($rtype:tt)*} ] } => (
$crate::argparse::ParamDescription {
name: stringify!($pname),
is_optional: true
@ -401,6 +410,19 @@ macro_rules! py_argparse_extract {
Err(e) => Err(e)
}
};
// optional parameter with reference extraction
( $py:expr, $iter:expr, $body:block,
[ { $pname:ident : $ptype:ty = [ {} {$default:expr} {$rtype:ty} ] } $($tail:tt)* ]
) => {
//unwrap() asserts the iterated sequence is long enough (which should be guaranteed);
match <$rtype as $crate::RefFromPyObject>::with_extracted($py,
$iter.next().unwrap().as_ref().unwrap_or($default.into_py_object($py).as_object()),
|$pname: $ptype| py_argparse_extract!($py, $iter, $body, [$($tail)*])
) {
Ok(v) => v,
Err(e) => Err(e)
}
};
}
#[cfg(test)]
@ -443,9 +465,10 @@ mod test {
let gil_guard = Python::acquire_gil();
let py = gil_guard.python();
let mut called = false;
let tuple = (0,).to_py_object(py);
py_argparse!(py, None, &tuple, None, (x: usize = 42) {
let tuple = (0, "foo").to_py_object(py);
py_argparse!(py, None, &tuple, None, (x: usize = 42, y: &str = "abc") {
assert_eq!(x, 0);
assert_eq!(y, "foo");
called = true;
Ok(())
}).unwrap();
@ -453,8 +476,9 @@ mod test {
let mut called = false;
let tuple = PyTuple::new(py, &[]);
py_argparse!(py, None, &tuple, None, (x: usize = 42) {
py_argparse!(py, None, &tuple, None, (x: usize = 42, y: &str = "abc") {
assert_eq!(x, 42);
assert_eq!(y, "abc");
called = true;
Ok(())
}).unwrap();

View file

@ -59,20 +59,20 @@
//! extern crate cpython;
//!
//! use cpython::{Python, PyDict, PyResult};
//!
//!
//! fn main() {
//! let gil = Python::acquire_gil();
//! hello(gil.python()).unwrap();
//! }
//!
//!
//! fn hello(py: Python) -> PyResult<()> {
//! let sys = py.import("sys")?;
//! let version: String = sys.get(py, "version")?.extract(py)?;
//!
//!
//! let locals = PyDict::new(py);
//! locals.set_item(py, "os", py.import("os")?)?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?;
//!
//!
//! println!("Hello {}, I'm Python {}", user, version);
//! Ok(())
//! }
@ -238,7 +238,7 @@ pub mod _detail {
/// ```
/// The full example project can be found at:
/// https://github.com/dgrunwald/rust-cpython/tree/master/extensions/hello
///
///
/// Rust will compile the code into a file named `libhello.so`, but we have to
/// rename the file in order to use it with Python:
///
@ -357,4 +357,3 @@ pub unsafe fn py_module_initializer_impl(
mem::forget(guard);
ret
}