#40: split ExtractPyObject into two traits:
* FromPyObject for all conversions that don't need to borrow temporaries * RefFromPyObject for extracting references out of temporaries (currently only used for extracting `&str`)
This commit is contained in:
parent
1a6e26f3c3
commit
0222176836
|
@ -11,13 +11,15 @@ py_module_initializer!(hello, inithello, PyInit_hello, |py, m| {
|
|||
Ok(())
|
||||
});
|
||||
|
||||
fn run(py: Python, args: &PyTuple, kwargs: &PyDict) -> PyResult<PyObject> {
|
||||
fn run(py: Python, args: &PyTuple, kwargs: Option<&PyDict>) -> PyResult<PyObject> {
|
||||
println!("Rust says: Hello Python!");
|
||||
for arg in args.iter(py) {
|
||||
println!("Rust got {}", arg);
|
||||
}
|
||||
for (key, val) in kwargs.items(py) {
|
||||
println!("{} = {}", key, val);
|
||||
if let Some(kwargs) = kwargs {
|
||||
for (key, val) in kwargs.items(py) {
|
||||
println!("{} = {}", key, val);
|
||||
}
|
||||
}
|
||||
Ok(py.None())
|
||||
}
|
||||
|
|
137
src/argparse.rs
137
src/argparse.rs
|
@ -168,13 +168,23 @@ macro_rules! py_argparse_parse_plist_impl {
|
|||
{ $callback:ident { $($initial_arg:tt)* } $output:tt ( ) } => {
|
||||
$callback! { $($initial_arg)* $output }
|
||||
};
|
||||
// Kwargs parameter with reference extraction
|
||||
{ $callback:ident $initial_args:tt [ $($output:tt)* ]
|
||||
( ** $name:ident : &$t:ty , $($tail:tt)* )
|
||||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:&$t = [ {**} {} {$t} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
// Kwargs parameter
|
||||
{ $callback:ident $initial_args:tt [ $($output:tt)* ]
|
||||
( ** $name:ident : $t:ty , $($tail:tt)* )
|
||||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:$t = [ {**} {} ] } ]
|
||||
[ $($output)* { $name:$t = [ {**} {} {} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
|
@ -184,7 +194,17 @@ macro_rules! py_argparse_parse_plist_impl {
|
|||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:&$crate::PyDict = [ {**} {} ] } ]
|
||||
[ $($output)* { $name:Option<&$crate::PyDict> = [ {**} {} {} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
// Varargs parameter with reference extraction
|
||||
{ $callback:ident $initial_args:tt [ $($output:tt)* ]
|
||||
( * $name:ident : &$t:ty , $($tail:tt)* )
|
||||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:&$t = [ {*} {} {$t} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
|
@ -194,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)*)
|
||||
}
|
||||
};
|
||||
|
@ -204,7 +224,17 @@ macro_rules! py_argparse_parse_plist_impl {
|
|||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:&$crate::PyTuple = [ {*} {} ] } ]
|
||||
[ $($output)* { $name:&$crate::PyTuple = [ {*} {} {} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
// Simple parameter with reference extraction
|
||||
{ $callback:ident $initial_args:tt [ $($output:tt)* ]
|
||||
( $name:ident : &$t:ty , $($tail:tt)* )
|
||||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:&$t = [ {} {} {$t} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
|
@ -214,7 +244,7 @@ macro_rules! py_argparse_parse_plist_impl {
|
|||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:$t = [ {} {} ] } ]
|
||||
[ $($output)* { $name:$t = [ {} {} {} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
|
@ -224,17 +254,18 @@ macro_rules! py_argparse_parse_plist_impl {
|
|||
} => {
|
||||
py_argparse_parse_plist_impl! {
|
||||
$callback $initial_args
|
||||
[ $($output)* { $name:&$crate::PyObject = [ {} {} ] } ]
|
||||
[ $($output)* { $name:&$crate::PyObject = [ {} {} {} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
// Optional parameter
|
||||
// TODO: 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} ] } ]
|
||||
[ $($output)* { $name:$t = [ {} {$default} {} ] } ]
|
||||
($($tail)*)
|
||||
}
|
||||
};
|
||||
|
@ -249,19 +280,15 @@ macro_rules! py_argparse_impl {
|
|||
// so we can directly pass along our inputs without calling parse_args().
|
||||
($py:expr, $fname:expr, $args:expr, $kwargs:expr, $body:block,
|
||||
[
|
||||
{ $pargs:ident : $pargs_type:ty = [ {*} {} ] }
|
||||
{ $pkwargs:ident : $pkwargs_type:ty = [ {**} {} ] }
|
||||
{ $pargs:ident : $pargs_type:ty = [ {*} {} {} ] }
|
||||
{ $pkwargs:ident : $pkwargs_type:ty = [ {**} {} {} ] }
|
||||
]
|
||||
) => {{
|
||||
let py: $crate::Python = $py;
|
||||
let _py: $crate::Python = $py;
|
||||
// TODO: use extract() to be more flexible in which type is expected
|
||||
let $pargs: $pargs_type = $args;
|
||||
let new_dict = if $kwargs.is_none() { Some($crate::PyDict::new(py)) } else { None };
|
||||
let ret = {
|
||||
let $pkwargs: $pkwargs_type = $kwargs.unwrap_or_else(|| new_dict.as_ref().unwrap());
|
||||
$body
|
||||
};
|
||||
$crate::PyDrop::release_ref(new_dict, $py);
|
||||
ret
|
||||
let $pkwargs: $pkwargs_type = $kwargs;
|
||||
$body
|
||||
}};
|
||||
|
||||
// normal argparse logic
|
||||
|
@ -320,7 +347,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 = [ {} {} $rtype:tt ] } => (
|
||||
$crate::argparse::ParamDescription {
|
||||
name: stringify!($pname),
|
||||
is_optional: false
|
||||
|
@ -335,57 +362,31 @@ 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).
|
||||
match <$ptype as $crate::ExtractPyObject>::prepare_extract($py, $iter.next().unwrap().as_ref().unwrap()) {
|
||||
Ok(prepared) => {
|
||||
match <$ptype as $crate::ExtractPyObject>::extract($py, &prepared) {
|
||||
Ok($pname) => py_argparse_extract!($py, $iter, $body, [$($tail)*]),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
},
|
||||
match <$ptype as $crate::FromPyObject>::extract($py, $iter.next().unwrap().as_ref().unwrap()) {
|
||||
Ok($pname) => py_argparse_extract!($py, $iter, $body, [$($tail)*]),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
};
|
||||
// normal parameter with reference extraction
|
||||
( $py:expr, $iter:expr, $body:block,
|
||||
[ { $pname:ident : $ptype:ty = [ {} {} {$rtype: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).
|
||||
match <$rtype as $crate::RefFromPyObject>::with_extracted($py,
|
||||
$iter.next().unwrap().as_ref().unwrap(),
|
||||
|$pname: $ptype| py_argparse_extract!($py, $iter, $body, [$($tail)*])
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_argparse_declare_item_in_impl {
|
||||
// argparse_declare_item_in_impl!({implhead} {head} (params) (,plist,) {tail} )
|
||||
// = implhead { head(params, pname:ptype...) tail }
|
||||
|
||||
{ {$($implhead:tt)*} {$($head:tt)*} $params:tt ( $(,)* ) {$($tail:tt)*} } => {
|
||||
py_coerce_item!{
|
||||
$($implhead)* {
|
||||
$($head)* $params $($tail)*
|
||||
}
|
||||
}
|
||||
};
|
||||
{ $implhead:tt $head:tt ($($params:tt)*) ( ,$pname:ident : $ptype:ty, $($r:tt)* ) $tail:tt } => {
|
||||
py_argparse_declare_item_in_impl!( $implhead $head ($($params)* , $pname : $ptype) ( ,$($r)* ) $tail)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_argparse_call_with_names {
|
||||
// py_argparse_call_with_names!(f, (lhs) (,plist,))
|
||||
// = f(lhs, pnames...)
|
||||
|
||||
( $f:expr, $lhs:tt ( $(,)* )) => (
|
||||
py_coerce_expr!{ $f $lhs }
|
||||
);
|
||||
( $f:expr, ($($lhs:tt)*) ( ,$pname:ident : $ptype:ty, $($r:tt)* )) => {
|
||||
py_argparse_call_with_names!( $f, ($($lhs)* , $pname) ( ,$($r)* ))
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use python::{Python, PythonObject};
|
||||
|
@ -405,5 +406,19 @@ mod test {
|
|||
}).unwrap();
|
||||
assert!(called);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_default_param_type() {
|
||||
let gil_guard = Python::acquire_gil();
|
||||
let py = gil_guard.python();
|
||||
let mut called = false;
|
||||
let tuple = ("abc",).to_py_object(py);
|
||||
py_argparse!(py, None, &tuple, None, (x) {
|
||||
assert_eq!(*x, tuple.get_item(py, 0));
|
||||
called = true;
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
assert!(called);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,13 +72,16 @@ pub trait ToPyObject {
|
|||
// -> into_py_object() allocates new Python object
|
||||
}
|
||||
|
||||
py_impl_to_py_object_for_python_object!(PyObject);
|
||||
|
||||
/// FromPyObject is implemented by various types that can be extracted from a Python object.
|
||||
///
|
||||
/// Usage:
|
||||
/// Normal usage is through the `PyObject::extract` helper method:
|
||||
/// ```let obj: PyObject = ...;
|
||||
/// let prepared = <TargetType as ExtractPyObject>::prepare_extract(&obj);
|
||||
/// let extracted = try!(extract(&prepared));```
|
||||
///
|
||||
/// let value = try!(obj.extract::<TargetType>(py));
|
||||
/// ```
|
||||
///
|
||||
/// TODO: update this documentation
|
||||
/// Note: depending on the implementation, the lifetime of the extracted result may
|
||||
/// depend on the lifetime of the `obj` or the `prepared` variable.
|
||||
///
|
||||
|
@ -91,14 +94,36 @@ pub trait ToPyObject {
|
|||
///
|
||||
/// In cases where the result does not depend on the `'prepared` lifetime,
|
||||
/// the inherent method `PyObject::extract()` can be used.
|
||||
pub trait ExtractPyObject<'prepared> : Sized {
|
||||
type Prepared : 'static;
|
||||
|
||||
fn prepare_extract<'a, 'p>(py: Python<'p>, obj: &'a PyObject) -> PyResult<Self::Prepared>;
|
||||
|
||||
fn extract<'p>(py: Python<'p>, prepared: &'prepared Self::Prepared) -> PyResult<Self>;
|
||||
pub trait FromPyObject<'source> : Sized {
|
||||
/// Extracts `Self` from the source `PyObject`.
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self>;
|
||||
}
|
||||
|
||||
|
||||
py_impl_from_py_object_for_python_object!(PyObject);
|
||||
|
||||
|
||||
|
||||
pub trait RefFromPyObject {
|
||||
fn with_extracted<F, R>(py: Python, obj: &PyObject, f: F) -> PyResult<R>
|
||||
where F: FnOnce(&Self) -> R;
|
||||
}
|
||||
|
||||
impl <T: ?Sized> RefFromPyObject for T
|
||||
where for<'a> &'a T: FromPyObject<'a>
|
||||
{
|
||||
#[inline]
|
||||
fn with_extracted<F, R>(py: Python, obj: &PyObject, f: F) -> PyResult<R>
|
||||
where F: FnOnce(&Self) -> R
|
||||
{
|
||||
match FromPyObject::extract(py, obj) {
|
||||
Ok(val) => Ok(f(val)),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl <'prepared, T> ExtractPyObject<'prepared> for T
|
||||
where T: PythonObjectWithCheckedDowncast
|
||||
{
|
||||
|
@ -114,6 +139,7 @@ where T: PythonObjectWithCheckedDowncast
|
|||
Ok(try!(obj.clone_ref(py).cast_into(py)))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// ToPyObject for references
|
||||
impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
|
||||
|
@ -157,7 +183,20 @@ impl <T> ToPyObject for Option<T> where T: ToPyObject {
|
|||
}
|
||||
}
|
||||
|
||||
impl <'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'source> {
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
|
||||
if obj.as_ptr() == unsafe { ffi::Py_None() } {
|
||||
Ok(None)
|
||||
} else {
|
||||
match T::extract(py, obj) {
|
||||
Ok(v) => Ok(Some(v)),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl <'prepared, T> ExtractPyObject<'prepared> for Option<T>
|
||||
where T: ExtractPyObject<'prepared>
|
||||
{
|
||||
|
@ -183,5 +222,5 @@ where T: ExtractPyObject<'prepared>
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
|
50
src/lib.rs
50
src/lib.rs
|
@ -97,7 +97,7 @@ pub use err::{PyErr, PyResult};
|
|||
pub use objects::*;
|
||||
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectDowncastError, PythonObjectWithTypeObject, PyClone, PyDrop};
|
||||
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
||||
pub use conversion::{ExtractPyObject, ToPyObject};
|
||||
pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject};
|
||||
pub use objectprotocol::{ObjectProtocol};
|
||||
|
||||
#[cfg(feature="python27-sys")]
|
||||
|
@ -131,6 +131,54 @@ macro_rules! py_replace_expr {
|
|||
($_t:tt $sub:expr) => {$sub};
|
||||
}
|
||||
|
||||
#[macro_export] #[doc(hidden)]
|
||||
macro_rules! py_impl_to_py_object_for_python_object {
|
||||
($T: ty) => (
|
||||
/// Identity conversion: allows using existing `PyObject` instances where
|
||||
/// `T: ToPyObject` is expected.
|
||||
impl $crate::ToPyObject for $T {
|
||||
type ObjectType = $T;
|
||||
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: $crate::Python) -> $T {
|
||||
$crate::PyClone::clone_ref(self, py)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_py_object(self, _py: $crate::Python) -> $T {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
|
||||
where F: FnOnce(*mut $crate::_detail::ffi::PyObject) -> R
|
||||
{
|
||||
f($crate::PythonObject::as_object(self).as_ptr())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[macro_export] #[doc(hidden)]
|
||||
macro_rules! py_impl_from_py_object_for_python_object {
|
||||
($T:ty) => {
|
||||
impl <'source> $crate::FromPyObject<'source> for $T {
|
||||
#[inline]
|
||||
fn extract(py: $crate::Python, obj: &'source $crate::PyObject) -> $crate::PyResult<$T> {
|
||||
use $crate::PyClone;
|
||||
Ok(try!(obj.clone_ref(py).cast_into::<$T>(py)))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'source> $crate::FromPyObject<'source> for &'source $T {
|
||||
#[inline]
|
||||
fn extract(py: $crate::Python, obj: &'source $crate::PyObject) -> $crate::PyResult<&'source $T> {
|
||||
Ok(try!(obj.cast_as::<$T>(py)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod python;
|
||||
mod err;
|
||||
mod conversion;
|
||||
|
|
|
@ -2,7 +2,7 @@ use ffi;
|
|||
use python::Python;
|
||||
use err::PyResult;
|
||||
use super::PyObject;
|
||||
use conversion::{ExtractPyObject, ToPyObject};
|
||||
use conversion::{ToPyObject};
|
||||
|
||||
/// Represents a Python `bool`.
|
||||
pub struct PyBool(PyObject);
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use python::{Python, PythonObject, ToPythonPointer, PyClone};
|
||||
use python::{Python, PythonObject, ToPythonPointer, PyClone, PyDrop};
|
||||
use err::{self, PyErr, PyResult};
|
||||
use super::object::PyObject;
|
||||
use ffi::{self, Py_ssize_t};
|
||||
use conversion::{ToPyObject, ExtractPyObject};
|
||||
use conversion::{ToPyObject, FromPyObject};
|
||||
|
||||
/// Represents a Python `list`.
|
||||
pub struct PyList(PyObject);
|
||||
|
@ -123,28 +123,40 @@ impl <T> ToPyObject for [T] where T: ToPyObject {
|
|||
}
|
||||
}
|
||||
|
||||
impl <'prepared, T> ExtractPyObject<'prepared> for Vec<T>
|
||||
where T: ExtractPyObject<'prepared>
|
||||
{
|
||||
type Prepared = Vec<T::Prepared>;
|
||||
impl <T> ToPyObject for Vec<T> where T: ToPyObject {
|
||||
type ObjectType = PyList;
|
||||
|
||||
fn prepare_extract(py: Python, obj: &PyObject) -> PyResult<Self::Prepared> {
|
||||
fn to_py_object(&self, py: Python) -> PyList {
|
||||
self.as_slice().to_py_object(py)
|
||||
}
|
||||
|
||||
fn into_py_object(self, py: Python) -> PyList {
|
||||
unsafe {
|
||||
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
|
||||
let t = err::cast_from_owned_ptr_or_panic(py, ptr);
|
||||
for (i, e) in self.into_iter().enumerate() {
|
||||
let obj = e.into_py_object(py).into_object();
|
||||
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj.steal_ptr());
|
||||
}
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'source, T> FromPyObject<'source> for Vec<T>
|
||||
where for<'a> T: FromPyObject<'a>
|
||||
{
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
|
||||
let list = try!(obj.cast_as::<PyList>(py));
|
||||
let len = list.len(py);
|
||||
let mut v = Vec::with_capacity(len);
|
||||
for i in 0 .. len {
|
||||
v.push(try!(T::prepare_extract(py, &list.get_item(py, i))));
|
||||
let item = list.get_item(py, i);
|
||||
v.push(try!(T::extract(py, &item)));
|
||||
item.release_ref(py);
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn extract(py: Python, prepared: &'prepared Self::Prepared) -> PyResult<Vec<T>> {
|
||||
let mut v = Vec::with_capacity(prepared.len());
|
||||
for prepared_elem in prepared {
|
||||
v.push(try!(T::extract(py, prepared_elem)));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -38,38 +38,10 @@ pub use self::num::PyLong as PyInt;
|
|||
pub use self::num::{PyLong, PyFloat};
|
||||
pub use self::sequence::PySequence;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! pyobject_to_pyobject(
|
||||
($name: ident) => (
|
||||
/// Identity conversion: allows using existing `PyObject` instances where
|
||||
/// `T: ToPyObject` is expected.
|
||||
impl $crate::ToPyObject for $name {
|
||||
type ObjectType = $name;
|
||||
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: $crate::Python) -> $name {
|
||||
$crate::PyClone::clone_ref(self, py)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_py_object(self, _py: $crate::Python) -> $name {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
|
||||
where F: FnOnce(*mut $crate::_detail::ffi::PyObject) -> R
|
||||
{
|
||||
f($crate::PythonObject::as_object(self).as_ptr())
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
macro_rules! pyobject_newtype(
|
||||
($name: ident) => (
|
||||
pyobject_to_pyobject!($name);
|
||||
py_impl_to_py_object_for_python_object!($name);
|
||||
py_impl_from_py_object_for_python_object!($name);
|
||||
|
||||
impl $crate::PythonObject for $name {
|
||||
#[inline]
|
||||
|
@ -138,17 +110,10 @@ macro_rules! pyobject_newtype(
|
|||
|
||||
macro_rules! extract(
|
||||
($obj:ident to $t:ty; $py:ident => $body: block) => {
|
||||
impl <'prepared> ::conversion::ExtractPyObject<'prepared>
|
||||
impl <'source> ::conversion::FromPyObject<'source>
|
||||
for $t
|
||||
{
|
||||
type Prepared = PyObject;
|
||||
|
||||
#[inline]
|
||||
fn prepare_extract(py: Python, obj: &PyObject) -> PyResult<Self::Prepared> {
|
||||
Ok(::python::PyClone::clone_ref(obj, py))
|
||||
}
|
||||
|
||||
fn extract($py: Python, $obj: &'prepared PyObject) -> PyResult<Self> {
|
||||
fn extract($py: Python, $obj: &'source PyObject) -> PyResult<Self> {
|
||||
$body
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ use err::{self, PyResult, PyErr};
|
|||
use super::object::PyObject;
|
||||
use super::exc;
|
||||
use ffi;
|
||||
use conversion::{ToPyObject, ExtractPyObject};
|
||||
use conversion::{ToPyObject, FromPyObject};
|
||||
|
||||
/// Represents a Python `int` object.
|
||||
///
|
||||
|
@ -193,16 +193,9 @@ macro_rules! int_convert_u64_or_i64 (
|
|||
}
|
||||
}
|
||||
|
||||
impl <'prepared> ExtractPyObject<'prepared> for $rust_type {
|
||||
type Prepared = PyObject;
|
||||
|
||||
#[inline]
|
||||
fn prepare_extract(py: Python, obj: &PyObject) -> PyResult<Self::Prepared> {
|
||||
Ok(obj.clone_ref(py))
|
||||
}
|
||||
|
||||
impl <'source> FromPyObject<'source> for $rust_type {
|
||||
#[cfg(feature="python27-sys")]
|
||||
fn extract(py: Python, obj: &'prepared PyObject) -> PyResult<$rust_type> {
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<$rust_type> {
|
||||
let ptr = obj.as_ptr();
|
||||
|
||||
unsafe {
|
||||
|
@ -221,7 +214,7 @@ macro_rules! int_convert_u64_or_i64 (
|
|||
}
|
||||
|
||||
#[cfg(feature="python3-sys")]
|
||||
fn extract(py: Python, obj: &'prepared PyObject) -> PyResult<$rust_type> {
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<$rust_type> {
|
||||
let ptr = obj.as_ptr();
|
||||
unsafe {
|
||||
if ffi::PyLong_Check(ptr) != 0 {
|
||||
|
|
|
@ -102,8 +102,6 @@ fn unpack_shared(ptr: *mut ffi::PyObject) -> *mut ffi::PyObject {
|
|||
ptr
|
||||
}
|
||||
|
||||
pyobject_to_pyobject!(PyObject);
|
||||
|
||||
impl PythonObject for PyObject {
|
||||
#[inline]
|
||||
fn as_object(&self) -> &PyObject {
|
||||
|
@ -277,11 +275,10 @@ impl PyObject {
|
|||
/// Extracts some type from the Python object.
|
||||
/// This is a wrapper function around `FromPyObject::from_py_object()`.
|
||||
#[inline]
|
||||
pub fn extract<T>(&self, py: Python) -> PyResult<T>
|
||||
where T: for<'prep> ::conversion::ExtractPyObject<'prep>
|
||||
pub fn extract<'a, T>(&'a self, py: Python) -> PyResult<T>
|
||||
where T: ::conversion::FromPyObject<'a>
|
||||
{
|
||||
let prepared = try!(<T as ::conversion::ExtractPyObject>::prepare_extract(py, self));
|
||||
<T as ::conversion::ExtractPyObject>::extract(py, &prepared)
|
||||
::conversion::FromPyObject::extract(py, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ use ffi;
|
|||
use python::{Python, PythonObject, PyClone, ToPythonPointer, PythonObjectDowncastError};
|
||||
use super::{exc, PyObject};
|
||||
use err::{self, PyResult, PyErr};
|
||||
use conversion::{ExtractPyObject, ToPyObject};
|
||||
use conversion::{FromPyObject, RefFromPyObject, ToPyObject};
|
||||
|
||||
/// Represents a Python string.
|
||||
/// Corresponds to `basestring` in Python 2, and `str` in Python 3.
|
||||
|
@ -288,10 +288,6 @@ impl PyString {
|
|||
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
|
||||
self.data(py).to_string_lossy()
|
||||
}
|
||||
|
||||
fn extract<'a>(py: Python, o: &'a PyObject) -> PyResult<Cow<'a, str>> {
|
||||
try!(o.cast_as::<PyString>(py)).to_string(py)
|
||||
}
|
||||
}
|
||||
|
||||
impl PyBytes {
|
||||
|
@ -425,50 +421,34 @@ impl ToPyObject for String {
|
|||
/// Allows extracting strings from Python objects.
|
||||
/// Accepts Python `str` and `unicode` objects.
|
||||
/// In Python 2.7, `str` is expected to be UTF-8 encoded.
|
||||
extract!(obj to String; py => {
|
||||
PyString::extract(py, obj).map(|s| s.into_owned())
|
||||
});
|
||||
impl <'source> FromPyObject<'source> for Cow<'source, str> {
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
|
||||
try!(obj.cast_as::<PyString>(py)).to_string(py)
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows extracting strings from Python objects.
|
||||
/// Accepts Python `str` and `unicode` objects.
|
||||
/// In Python 2.7, `str` is expected to be UTF-8 encoded.
|
||||
extract!(obj to Cow<'prepared, str>; py => {
|
||||
PyString::extract(py, obj)
|
||||
});
|
||||
|
||||
/// Used in `impl ExtractPyObject for &str`.
|
||||
pub enum PreparedString {
|
||||
Extracted(String),
|
||||
BorrowFrom(PyObject)
|
||||
impl <'source> FromPyObject<'source> for String {
|
||||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
|
||||
obj.extract::<Cow<str>>(py).map(Cow::into_owned)
|
||||
}
|
||||
}
|
||||
|
||||
impl <'prepared> ExtractPyObject<'prepared> for &'prepared str {
|
||||
type Prepared = PreparedString;
|
||||
|
||||
fn prepare_extract(py: Python, obj: &PyObject) -> PyResult<Self::Prepared> {
|
||||
match try!(PyString::extract(py, obj)) {
|
||||
Cow::Owned(s) => Ok(PreparedString::Extracted(s)),
|
||||
Cow::Borrowed(_) => Ok(PreparedString::BorrowFrom(obj.clone_ref(py)))
|
||||
}
|
||||
}
|
||||
|
||||
fn extract(py: Python, prepared: &'prepared PreparedString) -> PyResult<Self> {
|
||||
match *prepared {
|
||||
PreparedString::Extracted(ref s) => Ok(s),
|
||||
PreparedString::BorrowFrom(ref obj) => {
|
||||
match try!(PyString::extract(py, obj)) {
|
||||
Cow::Owned(_) => panic!("Failed to borrow from python object"),
|
||||
Cow::Borrowed(s) => Ok(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl RefFromPyObject for str {
|
||||
fn with_extracted<F, R>(py: Python, obj: &PyObject, f: F) -> PyResult<R>
|
||||
where F: FnOnce(&str) -> R
|
||||
{
|
||||
let s = try!(obj.extract::<Cow<str>>(py));
|
||||
Ok(f(&s))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use python::{Python, PythonObject};
|
||||
use conversion::{ToPyObject, ExtractPyObject};
|
||||
use conversion::{ToPyObject, RefFromPyObject};
|
||||
|
||||
#[test]
|
||||
fn test_non_bmp() {
|
||||
|
@ -485,8 +465,13 @@ mod test {
|
|||
let py = gil.python();
|
||||
let s = "Hello Python";
|
||||
let py_string = s.to_py_object(py).into_object();
|
||||
let prepared = <&str>::prepare_extract(py, &py_string).unwrap();
|
||||
assert_eq!(s, <&str>::extract(py, &prepared).unwrap());
|
||||
let mut called = false;
|
||||
RefFromPyObject::with_extracted(py, &py_string,
|
||||
|s2: &str| {
|
||||
assert_eq!(s, s2);
|
||||
called = true;
|
||||
}).unwrap();
|
||||
assert!(called);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use err::{self, PyErr, PyResult};
|
|||
use super::object::PyObject;
|
||||
use super::exc;
|
||||
use ffi::{self, Py_ssize_t};
|
||||
use conversion::{ToPyObject, ExtractPyObject};
|
||||
use conversion::ToPyObject;
|
||||
use std::slice;
|
||||
|
||||
/// Represents a Python tuple object.
|
||||
|
@ -159,21 +159,19 @@ fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr
|
|||
PyErr::new_lazy_init(py.get_type::<exc::ValueError>(), Some(msg.to_py_object(py).into_object()))
|
||||
}
|
||||
|
||||
macro_rules! id (($a:expr) => ($a));
|
||||
|
||||
macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => (
|
||||
impl <'p, $($T: ToPyObject),+> ToPyObject for ($($T,)+) {
|
||||
type ObjectType = PyTuple;
|
||||
|
||||
fn to_py_object(&self, py: Python) -> PyTuple {
|
||||
PyTuple::new(py, &[
|
||||
$(id!(self.$n.to_py_object(py)).into_object(),)+
|
||||
$(py_coerce_expr!(self.$n.to_py_object(py)).into_object(),)+
|
||||
])
|
||||
}
|
||||
|
||||
fn into_py_object(self, py: Python) -> PyTuple {
|
||||
PyTuple::new(py, &[
|
||||
$(id!(self.$n.into_py_object(py)).into_object(),)+
|
||||
$(py_coerce_expr!(self.$n.into_py_object(py)).into_object(),)+
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ base_case = '''
|
|||
} => {
|
||||
struct $class { _unsafe_inner: $crate::PyObject }
|
||||
|
||||
pyobject_to_pyobject!($class);
|
||||
py_impl_to_py_object_for_python_object!($class);
|
||||
py_impl_from_py_object_for_python_object!($class);
|
||||
|
||||
impl $crate::PythonObject for $class {
|
||||
#[inline]
|
||||
|
|
|
@ -42,7 +42,8 @@ macro_rules! py_class_impl {
|
|||
} => {
|
||||
struct $class { _unsafe_inner: $crate::PyObject }
|
||||
|
||||
pyobject_to_pyobject!($class);
|
||||
py_impl_to_py_object_for_python_object!($class);
|
||||
py_impl_from_py_object_for_python_object!($class);
|
||||
|
||||
impl $crate::PythonObject for $class {
|
||||
#[inline]
|
||||
|
|
|
@ -42,7 +42,8 @@ macro_rules! py_class_impl {
|
|||
} => {
|
||||
struct $class { _unsafe_inner: $crate::PyObject }
|
||||
|
||||
pyobject_to_pyobject!($class);
|
||||
py_impl_to_py_object_for_python_object!($class);
|
||||
py_impl_from_py_object_for_python_object!($class);
|
||||
|
||||
impl $crate::PythonObject for $class {
|
||||
#[inline]
|
||||
|
|
|
@ -273,13 +273,8 @@ macro_rules! py_class_binary_slot {
|
|||
|py| {
|
||||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<$class>();
|
||||
let arg = $crate::PyObject::from_borrowed_ptr(py, arg);
|
||||
let ret = match <$arg_type as $crate::ExtractPyObject>::prepare_extract(py, &arg) {
|
||||
Ok(prepared) => {
|
||||
match <$arg_type as $crate::ExtractPyObject>::extract(py, &prepared) {
|
||||
Ok(arg) => slf.$f(py, arg),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
},
|
||||
let ret = match <$arg_type as $crate::FromPyObject>::extract(py, &arg) {
|
||||
Ok(arg) => slf.$f(py, arg),
|
||||
Err(e) => Err(e)
|
||||
};
|
||||
$crate::PyDrop::release_ref(arg, py);
|
||||
|
@ -308,22 +303,10 @@ macro_rules! py_class_ternary_slot {
|
|||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<$class>();
|
||||
let arg1 = $crate::PyObject::from_borrowed_ptr(py, arg1);
|
||||
let arg2 = $crate::PyObject::from_borrowed_ptr(py, arg2);
|
||||
let ret = match <$arg1_type as $crate::ExtractPyObject>::prepare_extract(py, &arg1) {
|
||||
Ok(prepared1) => {
|
||||
match <$arg1_type as $crate::ExtractPyObject>::extract(py, &prepared1) {
|
||||
Ok(arg1) => {
|
||||
match <$arg2_type as $crate::ExtractPyObject>::prepare_extract(py, &arg2) {
|
||||
Ok(prepared2) => {
|
||||
match <$arg2_type as $crate::ExtractPyObject>::extract(py, &prepared2) {
|
||||
Ok(arg2) => slf.$f(py, arg1, arg2),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
let ret = match <$arg1_type as $crate::FromPyObject>::extract(py, &arg1) {
|
||||
Ok(arg1) => match <$arg2_type as $crate::FromPyObject>::extract(py, &arg2) {
|
||||
Ok(arg2) => slf.$f(py, arg1, arg2),
|
||||
Err(e) => Err(e)
|
||||
},
|
||||
Err(e) => Err(e)
|
||||
};
|
||||
|
@ -353,13 +336,8 @@ macro_rules! py_class_contains_slot {
|
|||
|py| {
|
||||
let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<$class>();
|
||||
let arg = $crate::PyObject::from_borrowed_ptr(py, arg);
|
||||
let ret = match <$arg_type as $crate::ExtractPyObject>::prepare_extract(py, &arg) {
|
||||
Ok(prepared) => {
|
||||
match <$arg_type as $crate::ExtractPyObject>::extract(py, &prepared) {
|
||||
Ok(arg) => slf.$f(py, arg),
|
||||
Err(e) => $crate::py_class::slots::type_error_to_false(py, e)
|
||||
}
|
||||
},
|
||||
let ret = match <$arg_type as $crate::FromPyObject>::extract(py, &arg) {
|
||||
Ok(arg) => slf.$f(py, arg),
|
||||
Err(e) => $crate::py_class::slots::type_error_to_false(py, e)
|
||||
};
|
||||
$crate::PyDrop::release_ref(arg, py);
|
||||
|
@ -404,14 +382,6 @@ macro_rules! py_class_binary_numeric_slot {
|
|||
}}
|
||||
}
|
||||
|
||||
pub fn type_error_to_not_implemented(py: Python, e: PyErr) -> PyResult<PyObject> {
|
||||
if e.matches(py, py.get_type::<exc::TypeError>()) {
|
||||
Ok(py.NotImplemented())
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UnitCallbackConverter;
|
||||
|
||||
impl CallbackConverter<()> for UnitCallbackConverter {
|
||||
|
|
Loading…
Reference in a new issue