Replace FromPyObject with the more powerful ExtractPyObject.
This is a [breaking-change] and makes the trait more difficult to implement. The usage through PyObject::extract() is unchanged. This change allows extracting a `&str` through a temporary `Cow<str>` without having to copy the string data from python to rust (at least in cases where the python string is UTF-8 encoded). This is preparation in hope I'll be able to make py_fn!() automatically extract the function arguments.
This commit is contained in:
parent
1ad27b977e
commit
45d03bf8bb
|
@ -71,14 +71,45 @@ pub trait ToPyObject<'p> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FromPyObject is implemented by various types that can be extracted from a Python object.
|
/// FromPyObject is implemented by various types that can be extracted from a Python object.
|
||||||
pub trait FromPyObject<'p> {
|
///
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, Self>;
|
/// Usage:
|
||||||
|
/// ```let obj: PyObject = ...;
|
||||||
|
/// let prepared = <TargetType as FromPyObject>::prepare_extract(&obj);
|
||||||
|
/// let extracted = try!(extract(&prepared));```
|
||||||
|
///
|
||||||
|
/// Note: depending on the implementation, the lifetime of the extracted result may
|
||||||
|
/// depend on the lifetime of the `obj` or the `prepared` variable.
|
||||||
|
///
|
||||||
|
/// For example, when extracting `&str` from a python byte string, the resulting string slice will
|
||||||
|
/// point to the existing string data (lifetime: `'source`).
|
||||||
|
/// On the other hand, when extracting `&str` from a python unicode string, the preparation step
|
||||||
|
/// will convert the string to UTF-8, and the resulting string slice will have lifetime `'prepared`.
|
||||||
|
/// Since only which of these cases applies depends on the runtime type of the python object,
|
||||||
|
/// both the `obj` and `prepared` variables must outlive the resulting string slice.
|
||||||
|
///
|
||||||
|
/// In cases where the result does not depend on the `'prepared` lifetime,
|
||||||
|
/// the inherent method `PyObject::extract()` can be used.
|
||||||
|
pub trait ExtractPyObject<'python, 'source, 'prepared> {
|
||||||
|
type Prepared;
|
||||||
|
|
||||||
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared>;
|
||||||
|
|
||||||
|
fn extract(prepared: &'prepared Self::Prepared) -> PyResult<'python, Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p, T> FromPyObject<'p> for T where T: PythonObjectWithCheckedDowncast<'p> {
|
impl <'python, 'source, 'prepared, T> ExtractPyObject<'python, 'source, 'prepared>
|
||||||
|
for T where T: PythonObjectWithCheckedDowncast<'python> {
|
||||||
|
|
||||||
|
type Prepared = &'source PyObject<'python>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_py_object(s : &PyObject<'p>) -> PyResult<'p, T> {
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
|
||||||
Ok(try!(s.clone().cast_into()))
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(&&ref obj: &'prepared Self::Prepared) -> PyResult<'python, T> {
|
||||||
|
Ok(try!(obj.clone().cast_into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub use err::{PyErr, PyResult};
|
||||||
pub use objects::*;
|
pub use objects::*;
|
||||||
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
|
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
|
||||||
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
||||||
pub use conversion::{FromPyObject, ToPyObject};
|
pub use conversion::{ExtractPyObject, ToPyObject};
|
||||||
pub use objectprotocol::{ObjectProtocol};
|
pub use objectprotocol::{ObjectProtocol};
|
||||||
pub use rustobject::{PyRustType, PyRustObject};
|
pub use rustobject::{PyRustType, PyRustObject};
|
||||||
pub use rustobject::typebuilder::PyRustTypeBuilder;
|
pub use rustobject::typebuilder::PyRustTypeBuilder;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use ffi;
|
||||||
use python::{Python, ToPythonPointer};
|
use python::{Python, ToPythonPointer};
|
||||||
use err::PyResult;
|
use err::PyResult;
|
||||||
use super::PyObject;
|
use super::PyObject;
|
||||||
use conversion::{FromPyObject, ToPyObject};
|
use conversion::{ExtractPyObject, ToPyObject};
|
||||||
|
|
||||||
/// Represents a Python `bool`.
|
/// Represents a Python `bool`.
|
||||||
pub struct PyBool<'p>(PyObject<'p>);
|
pub struct PyBool<'p>(PyObject<'p>);
|
||||||
|
@ -44,9 +44,7 @@ impl <'p> ToPyObject<'p> for bool {
|
||||||
/// Converts a Python `bool` to a rust `bool`.
|
/// Converts a Python `bool` to a rust `bool`.
|
||||||
///
|
///
|
||||||
/// Fails with `TypeError` if the input is not a Python `bool`.
|
/// Fails with `TypeError` if the input is not a Python `bool`.
|
||||||
impl <'p> FromPyObject<'p> for bool {
|
extract!(obj to bool => {
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, bool> {
|
Ok(try!(obj.cast_as::<PyBool>()).is_true())
|
||||||
Ok(try!(s.clone().cast_into::<PyBool>()).is_true())
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use python::{Python, PythonObject, ToPythonPointer};
|
||||||
use err::{self, PyResult};
|
use err::{self, PyResult};
|
||||||
use super::object::PyObject;
|
use super::object::PyObject;
|
||||||
use ffi::{self, Py_ssize_t};
|
use ffi::{self, Py_ssize_t};
|
||||||
use conversion::{ToPyObject, FromPyObject};
|
use conversion::{ToPyObject, ExtractPyObject};
|
||||||
|
|
||||||
/// Represents a Python `list`.
|
/// Represents a Python `list`.
|
||||||
pub struct PyList<'p>(PyObject<'p>);
|
pub struct PyList<'p>(PyObject<'p>);
|
||||||
|
@ -136,9 +136,19 @@ impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p, T> FromPyObject<'p> for Vec<T> where T: FromPyObject<'p> {
|
impl <'python, 'source, 'prepared, T> ExtractPyObject<'python, 'source, 'prepared>
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, Vec<T>> {
|
for Vec<T> where T: for<'s, 'p> ExtractPyObject<'python, 's, 'p> {
|
||||||
let list = try!(s.cast_as::<PyList>());
|
|
||||||
|
type Prepared = &'source PyObject<'python>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(&&ref obj: &'prepared Self::Prepared) -> PyResult<'python, Vec<T>> {
|
||||||
|
let list = try!(obj.cast_as::<PyList>());
|
||||||
let mut v = Vec::with_capacity(list.len());
|
let mut v = Vec::with_capacity(list.len());
|
||||||
for i in 0 .. list.len() {
|
for i in 0 .. list.len() {
|
||||||
v.push(try!(list.get_item(i).extract::<T>()));
|
v.push(try!(list.get_item(i).extract::<T>()));
|
||||||
|
|
|
@ -151,6 +151,27 @@ macro_rules! pyobject_newtype(
|
||||||
);
|
);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! extract(
|
||||||
|
($obj:ident to $t:ty => $body: block) => {
|
||||||
|
impl <'python, 'source, 'prepared>
|
||||||
|
::conversion::ExtractPyObject<'python, 'source, 'prepared>
|
||||||
|
for $t
|
||||||
|
{
|
||||||
|
|
||||||
|
type Prepared = &'source PyObject<'python>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract(&$obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, Self> {
|
||||||
|
$body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
mod object;
|
mod object;
|
||||||
mod typeobject;
|
mod typeobject;
|
||||||
mod module;
|
mod module;
|
||||||
|
|
|
@ -24,7 +24,7 @@ use err::{self, PyResult, PyErr};
|
||||||
use super::object::PyObject;
|
use super::object::PyObject;
|
||||||
use super::exc;
|
use super::exc;
|
||||||
use ffi;
|
use ffi;
|
||||||
use conversion::{ToPyObject, FromPyObject};
|
use conversion::{ToPyObject, ExtractPyObject};
|
||||||
|
|
||||||
/// Represents a Python `int` object.
|
/// Represents a Python `int` object.
|
||||||
///
|
///
|
||||||
|
@ -118,35 +118,17 @@ macro_rules! int_fits_c_long(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature="python27-sys")]
|
extract!(obj to $rust_type => {
|
||||||
impl <'p> FromPyObject<'p> for $rust_type {
|
let py = obj.python();
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> {
|
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
|
||||||
let py = s.python();
|
if val == -1 && PyErr::occurred(py) {
|
||||||
let val = unsafe { ffi::PyInt_AsLong(s.as_ptr()) };
|
return Err(PyErr::fetch(py));
|
||||||
if val == -1 && PyErr::occurred(py) {
|
|
||||||
return Err(PyErr::fetch(py));
|
|
||||||
}
|
|
||||||
match num::traits::cast::<c_long, $rust_type>(val) {
|
|
||||||
Some(v) => Ok(v),
|
|
||||||
None => Err(overflow_error(py))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
match num::traits::cast::<c_long, $rust_type>(val) {
|
||||||
|
Some(v) => Ok(v),
|
||||||
#[cfg(feature="python3-sys")]
|
None => Err(overflow_error(py))
|
||||||
impl <'p> FromPyObject<'p> for $rust_type {
|
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> {
|
|
||||||
let py = s.python();
|
|
||||||
let val = unsafe { ffi::PyLong_AsLong(s.as_ptr()) };
|
|
||||||
if val == -1 && PyErr::occurred(py) {
|
|
||||||
return Err(PyErr::fetch(py));
|
|
||||||
}
|
|
||||||
match num::traits::cast::<c_long, $rust_type>(val) {
|
|
||||||
Some(v) => Ok(v),
|
|
||||||
None => Err(overflow_error(py))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -162,16 +144,14 @@ macro_rules! int_fits_larger_int(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p> FromPyObject<'p> for $rust_type {
|
extract!(obj to $rust_type => {
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> {
|
let py = obj.python();
|
||||||
let py = s.python();
|
let val = try!(obj.extract::<$larger_type>());
|
||||||
let val = try!(s.extract::<$larger_type>());
|
match num::traits::cast::<$larger_type, $rust_type>(val) {
|
||||||
match num::traits::cast::<$larger_type, $rust_type>(val) {
|
Some(v) => Ok(v),
|
||||||
Some(v) => Ok(v),
|
None => Err(overflow_error(py))
|
||||||
None => Err(overflow_error(py))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -215,15 +195,24 @@ macro_rules! int_convert_u64_or_i64 (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p> FromPyObject<'p> for $rust_type {
|
impl <'python, 'source, 'prepared>
|
||||||
|
ExtractPyObject<'python, 'source, 'prepared> for $rust_type
|
||||||
|
{
|
||||||
|
type Prepared = &'source PyObject<'python>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature="python27-sys")]
|
#[cfg(feature="python27-sys")]
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> {
|
fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, $rust_type> {
|
||||||
let py = s.python();
|
let py = obj.python();
|
||||||
let ptr = s.as_ptr();
|
let ptr = obj.as_ptr();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::PyLong_Check(ptr) != 0 {
|
if ffi::PyLong_Check(ptr) != 0 {
|
||||||
err_if_invalid_value(s, !0, || $pylong_as_ull_or_ull(s.as_ptr()) )
|
err_if_invalid_value(&obj, !0, || $pylong_as_ull_or_ull(obj.as_ptr()) )
|
||||||
} else if ffi::PyInt_Check(ptr) != 0 {
|
} else if ffi::PyInt_Check(ptr) != 0 {
|
||||||
match num::traits::cast::<c_long, $rust_type>(ffi::PyInt_AS_LONG(ptr)) {
|
match num::traits::cast::<c_long, $rust_type>(ffi::PyInt_AS_LONG(ptr)) {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
|
@ -237,12 +226,12 @@ macro_rules! int_convert_u64_or_i64 (
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature="python3-sys")]
|
#[cfg(feature="python3-sys")]
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, $rust_type> {
|
fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, $rust_type> {
|
||||||
let py = s.python();
|
let py = obj.python();
|
||||||
let ptr = s.as_ptr();
|
let ptr = obj.as_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
if ffi::PyLong_Check(ptr) != 0 {
|
if ffi::PyLong_Check(ptr) != 0 {
|
||||||
err_if_invalid_value(s, !0, || $pylong_as_ull_or_ull(s.as_ptr()) )
|
err_if_invalid_value(&obj, !0, || $pylong_as_ull_or_ull(obj.as_ptr()) )
|
||||||
} else {
|
} else {
|
||||||
let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr)));
|
let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr)));
|
||||||
err_if_invalid_value(&num, !0, || $pylong_as_ull_or_ull(num.as_ptr()) )
|
err_if_invalid_value(&num, !0, || $pylong_as_ull_or_ull(num.as_ptr()) )
|
||||||
|
@ -291,17 +280,15 @@ impl <'p> ToPyObject<'p> for f64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p> FromPyObject<'p> for f64 {
|
extract!(obj to f64 => {
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, f64> {
|
let py = obj.python();
|
||||||
let py = s.python();
|
let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) };
|
||||||
let v = unsafe { ffi::PyFloat_AsDouble(s.as_ptr()) };
|
if v == -1.0 && PyErr::occurred(py) {
|
||||||
if v == -1.0 && PyErr::occurred(py) {
|
Err(PyErr::fetch(py))
|
||||||
Err(PyErr::fetch(py))
|
} else {
|
||||||
} else {
|
Ok(v)
|
||||||
Ok(v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
fn overflow_error(py: Python) -> PyErr {
|
fn overflow_error(py: Python) -> PyErr {
|
||||||
PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None)
|
PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None)
|
||||||
|
@ -315,11 +302,9 @@ impl <'p> ToPyObject<'p> for f32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p> FromPyObject<'p> for f32 {
|
extract!(obj to f32 => {
|
||||||
fn from_py_object(s: &PyObject<'p>) -> PyResult<'p, f32> {
|
Ok(try!(obj.extract::<f64>()) as f32)
|
||||||
Ok(try!(s.extract::<f64>()) as f32)
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
|
@ -243,8 +243,10 @@ impl <'p> PyObject<'p> {
|
||||||
/// Extracts some type from the Python object.
|
/// Extracts some type from the Python object.
|
||||||
/// This is a wrapper function around `FromPyObject::from_py_object()`.
|
/// This is a wrapper function around `FromPyObject::from_py_object()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extract<T>(&self) -> Result<T, PyErr<'p>> where T: ::conversion::FromPyObject<'p> {
|
pub fn extract<'s, T>(&'s self) -> Result<T, PyErr<'p>>
|
||||||
::conversion::FromPyObject::from_py_object(self)
|
where T: for<'prep> ::conversion::ExtractPyObject<'p, 's, 'prep> {
|
||||||
|
let prepared = try!(<T as ::conversion::ExtractPyObject>::prepare_extract(self));
|
||||||
|
<T as ::conversion::ExtractPyObject>::extract(&prepared)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ use ffi;
|
||||||
use python::{Python, PythonObject, ToPythonPointer};
|
use python::{Python, PythonObject, ToPythonPointer};
|
||||||
use super::{exc, PyObject};
|
use super::{exc, PyObject};
|
||||||
use err::{self, PyResult, PyErr};
|
use err::{self, PyResult, PyErr};
|
||||||
use conversion::{FromPyObject, ToPyObject};
|
use conversion::{ExtractPyObject, ToPyObject};
|
||||||
|
|
||||||
/// Represents a Python byte string.
|
/// Represents a Python byte string.
|
||||||
/// Corresponds to `str` in Python 2, and `bytes` in Python 3.
|
/// Corresponds to `str` in Python 2, and `bytes` in Python 3.
|
||||||
|
@ -281,21 +281,57 @@ impl <'p> ToPyObject<'p> 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 => {
|
||||||
|
PyString::extract(obj).map(|s| s.into_owned())
|
||||||
|
});
|
||||||
|
|
||||||
/// Allows extracting strings from Python objects.
|
/// Allows extracting strings from Python objects.
|
||||||
/// Accepts Python `str` and `unicode` objects.
|
/// Accepts Python `str` and `unicode` objects.
|
||||||
/// In Python 2.7, `str` is expected to be UTF-8 encoded.
|
/// In Python 2.7, `str` is expected to be UTF-8 encoded.
|
||||||
impl <'p> FromPyObject<'p> for String {
|
extract!(obj to Cow<'source, str> => {
|
||||||
fn from_py_object(o: &PyObject<'p>) -> PyResult<'p, String> {
|
PyString::extract(obj)
|
||||||
PyString::extract(o).map(|s| s.into_owned())
|
});
|
||||||
|
|
||||||
|
impl <'python, 'source, 'prepared> ExtractPyObject<'python, 'source, 'prepared> for &'prepared str {
|
||||||
|
|
||||||
|
type Prepared = Cow<'source, str>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
|
||||||
|
PyString::extract(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extract(cow: &'prepared Cow<'source, str>) -> PyResult<'python, Self> {
|
||||||
|
Ok(cow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn test_non_bmp() {
|
mod test {
|
||||||
let gil = Python::acquire_gil();
|
use python::{Python, PythonObject};
|
||||||
let py = gil.python();
|
use conversion::{ToPyObject, ExtractPyObject};
|
||||||
let s = "\u{1F30F}";
|
|
||||||
let py_string = s.to_py_object(py).into_object();
|
#[test]
|
||||||
assert_eq!(s, py_string.extract::<String>().unwrap());
|
fn test_non_bmp() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
let s = "\u{1F30F}";
|
||||||
|
let py_string = s.to_py_object(py).into_object();
|
||||||
|
assert_eq!(s, py_string.extract::<String>().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extract_str() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
let s = "Hello Python";
|
||||||
|
let py_string = s.to_py_object(py).into_object();
|
||||||
|
let prepared = <&str>::prepare_extract(&py_string).unwrap();
|
||||||
|
assert_eq!(s, <&str>::extract(&prepared).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use err::{self, PyResult, PyErr};
|
||||||
use super::object::PyObject;
|
use super::object::PyObject;
|
||||||
use super::exc;
|
use super::exc;
|
||||||
use ffi::{self, Py_ssize_t};
|
use ffi::{self, Py_ssize_t};
|
||||||
use conversion::{ToPyObject, FromPyObject};
|
use conversion::{ToPyObject, ExtractPyObject};
|
||||||
|
|
||||||
/// Represents a Python tuple object.
|
/// Represents a Python tuple object.
|
||||||
pub struct PyTuple<'p>(PyObject<'p>);
|
pub struct PyTuple<'p>(PyObject<'p>);
|
||||||
|
@ -219,14 +219,12 @@ impl <'p> ToPyObject<'p> for NoArgs {
|
||||||
|
|
||||||
/// Returns `Ok(NoArgs)` if the input is an empty Python tuple.
|
/// Returns `Ok(NoArgs)` if the input is an empty Python tuple.
|
||||||
/// Otherwise, returns an error.
|
/// Otherwise, returns an error.
|
||||||
impl <'p> FromPyObject<'p> for NoArgs {
|
extract!(obj to NoArgs => {
|
||||||
fn from_py_object(s : &PyObject<'p>) -> PyResult<'p, NoArgs> {
|
let t = try!(obj.cast_as::<PyTuple>());
|
||||||
let t = try!(s.cast_as::<PyTuple>());
|
if t.len() == 0 {
|
||||||
if t.len() == 0 {
|
Ok(NoArgs)
|
||||||
Ok(NoArgs)
|
} else {
|
||||||
} else {
|
Err(wrong_tuple_length(t, 0))
|
||||||
Err(wrong_tuple_length(t, 0))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue