Add back PyIterator, PyListIterator etc.
This commit is contained in:
parent
0a270a0583
commit
32086a0ef5
|
@ -136,7 +136,7 @@ mod sysmodule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 an
|
|||
mod intrcheck; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod import; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
|
||||
mod objectabstract; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod objectabstract;
|
||||
mod bltinmodule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
|
||||
#[cfg(Py_LIMITED_API)] mod code {}
|
||||
|
|
|
@ -2,6 +2,7 @@ use libc::{c_char, c_int, c_long};
|
|||
use pyport::Py_ssize_t;
|
||||
use object::PyObject;
|
||||
use moduleobject::PyModuleDef;
|
||||
#[cfg(Py_3_5)]
|
||||
use methodobject::PyMethodDef;
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -570,6 +570,10 @@ extern "C" {
|
|||
arg2: *mut Struct__Py_Identifier)
|
||||
-> c_int;*/
|
||||
pub fn PyObject_SelfIter(arg1: *mut PyObject) -> *mut PyObject;
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn _PyObject_NextNotImplemented(arg1: *mut PyObject) -> *mut PyObject;
|
||||
|
||||
pub fn PyObject_GenericGetAttr(arg1: *mut PyObject, arg2: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
pub fn PyObject_GenericSetAttr(arg1: *mut PyObject, arg2: *mut PyObject,
|
||||
|
|
|
@ -42,6 +42,10 @@ pub unsafe fn PyObject_Length(o: *mut PyObject) -> Py_ssize_t {
|
|||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg(all(not(Py_LIMITED_API), Py_3_4))]
|
||||
pub fn PyObject_LengthHint(o: *mut PyObject, arg1: Py_ssize_t)
|
||||
-> Py_ssize_t;
|
||||
|
||||
pub fn PyObject_GetItem(o: *mut PyObject, key: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
pub fn PyObject_SetItem(o: *mut PyObject, key: *mut PyObject,
|
||||
|
@ -64,16 +68,57 @@ extern "C" {
|
|||
buffer: *mut *mut c_void,
|
||||
buffer_len: *mut Py_ssize_t)
|
||||
-> c_int;
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[inline]
|
||||
pub unsafe fn PyObject_CheckBuffer(o: *mut PyObject) -> c_int {
|
||||
let tp_as_buffer = (*(*o).ob_type).tp_as_buffer;
|
||||
(!tp_as_buffer.is_null() && (*tp_as_buffer).bf_getbuffer.is_some()) as c_int
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
extern "C" {
|
||||
pub fn PyObject_GetBuffer(obj: *mut PyObject, view: *mut Py_buffer,
|
||||
flags: c_int) -> c_int;
|
||||
pub fn PyBuffer_GetPointer(view: *mut Py_buffer, indices: *mut Py_ssize_t)
|
||||
-> *mut c_void;
|
||||
pub fn PyBuffer_ToContiguous(buf: *mut c_void,
|
||||
view: *mut Py_buffer, len: Py_ssize_t,
|
||||
order: c_char) -> c_int;
|
||||
pub fn PyBuffer_FromContiguous(view: *mut Py_buffer,
|
||||
buf: *mut c_void, len: Py_ssize_t,
|
||||
order: c_char) -> c_int;
|
||||
pub fn PyObject_CopyData(dest: *mut PyObject, src: *mut PyObject)
|
||||
-> c_int;
|
||||
pub fn PyBuffer_IsContiguous(view: *const Py_buffer, fort: c_char)
|
||||
-> c_int;
|
||||
pub fn PyBuffer_FillContiguousStrides(ndims: c_int,
|
||||
shape: *mut Py_ssize_t,
|
||||
strides: *mut Py_ssize_t,
|
||||
itemsize: c_int,
|
||||
fort: c_char) -> ();
|
||||
pub fn PyBuffer_FillInfo(view: *mut Py_buffer, o: *mut PyObject,
|
||||
buf: *mut c_void, len: Py_ssize_t,
|
||||
readonly: c_int, flags: c_int)
|
||||
-> c_int;
|
||||
pub fn PyBuffer_Release(view: *mut Py_buffer) -> ();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn PyObject_Format(obj: *mut PyObject, format_spec: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
pub fn PyObject_GetIter(arg1: *mut PyObject) -> *mut PyObject;
|
||||
}
|
||||
|
||||
/* not available in limited ABI
|
||||
#define PyIter_Check(obj) \
|
||||
((obj)->ob_type->tp_iternext != NULL && \
|
||||
(obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented)
|
||||
*/
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[inline]
|
||||
pub unsafe fn PyIter_Check(o: *mut PyObject) -> c_int {
|
||||
(match (*(*o).ob_type).tp_iternext {
|
||||
Some(tp_iternext) => tp_iternext as *const c_void != ::object::_PyObject_NextNotImplemented as *const c_void,
|
||||
None => false
|
||||
}) as c_int
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn PyIter_Next(arg1: *mut PyObject) -> *mut PyObject;
|
||||
|
@ -85,6 +130,9 @@ extern "C" {
|
|||
-> *mut PyObject;
|
||||
pub fn PyNumber_Multiply(o1: *mut PyObject, o2: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
#[cfg(Py_3_5)]
|
||||
pub fn PyNumber_MatrixMultiply(o1: *mut PyObject, o2: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
pub fn PyNumber_FloorDivide(o1: *mut PyObject, o2: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
pub fn PyNumber_TrueDivide(o1: *mut PyObject, o2: *mut PyObject)
|
||||
|
@ -110,11 +158,12 @@ extern "C" {
|
|||
pub fn PyNumber_Or(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject;
|
||||
}
|
||||
|
||||
/*
|
||||
#define PyIndex_Check(obj) \
|
||||
((obj)->ob_type->tp_as_number != NULL && \
|
||||
(obj)->ob_type->tp_as_number->nb_index != NULL)
|
||||
*/
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[inline]
|
||||
pub unsafe fn PyIndex_Check(o: *mut PyObject) -> c_int {
|
||||
let tp_as_number = (*(*o).ob_type).tp_as_number;
|
||||
(!tp_as_number.is_null() && (*tp_as_number).nb_index.is_some()) as c_int
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn PyNumber_Index(o: *mut PyObject) -> *mut PyObject;
|
||||
|
@ -128,6 +177,9 @@ extern "C" {
|
|||
-> *mut PyObject;
|
||||
pub fn PyNumber_InPlaceMultiply(o1: *mut PyObject, o2: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
#[cfg(Py_3_5)]
|
||||
pub fn PyNumber_InPlaceMatrixMultiply(o1: *mut PyObject, o2: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
pub fn PyNumber_InPlaceFloorDivide(o1: *mut PyObject, o2: *mut PyObject)
|
||||
-> *mut PyObject;
|
||||
pub fn PyNumber_InPlaceTrueDivide(o1: *mut PyObject, o2: *mut PyObject)
|
||||
|
@ -180,6 +232,7 @@ extern "C" {
|
|||
pub fn PySequence_List(o: *mut PyObject) -> *mut PyObject;
|
||||
pub fn PySequence_Fast(o: *mut PyObject, m: *const c_char)
|
||||
-> *mut PyObject;
|
||||
// TODO: PySequence_Fast macros
|
||||
pub fn PySequence_Count(o: *mut PyObject, value: *mut PyObject)
|
||||
-> Py_ssize_t;
|
||||
pub fn PySequence_Contains(seq: *mut PyObject, ob: *mut PyObject)
|
||||
|
|
|
@ -209,16 +209,16 @@ pub trait ObjectProtocol : PythonObject {
|
|||
})
|
||||
}
|
||||
|
||||
/* TODO /// Takes an object and returns an iterator for it.
|
||||
/// Takes an object and returns an iterator for it.
|
||||
/// This is typically a new iterator but if the argument
|
||||
/// is an iterator, this returns itself.
|
||||
#[cfg(feature="python27-sys")]
|
||||
#[inline]
|
||||
fn iter(&self, py: Python) -> PyResult<::objects::PyIterator<'p>> {
|
||||
unsafe {
|
||||
err::result_cast_from_owned_ptr(self.python(), ffi::PyObject_GetIter(self.as_ptr()))
|
||||
}
|
||||
}*/
|
||||
fn iter<'p>(&self, py: Python<'p>) -> PyResult<::objects::PyIterator<'p>> {
|
||||
let obj = try!(unsafe {
|
||||
err::result_from_owned_ptr(py, ffi::PyObject_GetIter(self.as_ptr()))
|
||||
});
|
||||
Ok(try!(::objects::PyIterator::from_object(py, obj)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectProtocol for PyObject {}
|
||||
|
|
|
@ -48,5 +48,26 @@ extract!(obj to bool; py => {
|
|||
Ok(try!(obj.cast_as::<PyBool>(py)).is_true())
|
||||
});
|
||||
|
||||
// TODO: mod tests
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use python::{Python, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
|
||||
#[test]
|
||||
fn test_true() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
assert!(py.True().is_true());
|
||||
assert_eq!(true, py.True().as_object().extract(py).unwrap());
|
||||
assert!(true.to_py_object(py).as_object() == py.True().as_object());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_false() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
assert!(!py.False().is_true());
|
||||
assert_eq!(false, py.False().as_object().extract(py).unwrap());
|
||||
assert!(false.to_py_object(py).as_object() == py.False().as_object());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,7 +158,6 @@ impl <K, V> ToPyObject for collections::BTreeMap<K, V>
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std;
|
||||
use python::{Python, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
use objects::{PyDict, PyTuple};
|
||||
|
@ -248,9 +247,8 @@ mod test {
|
|||
assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated!
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
TODO fn test_items_list() {
|
||||
fn test_items_list() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let mut v = HashMap::new();
|
||||
|
@ -261,15 +259,14 @@ TODO fn test_items_list() {
|
|||
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
|
||||
let mut key_sum = 0;
|
||||
let mut value_sum = 0;
|
||||
for el in dict.items_list(py) {
|
||||
let tuple = el.cast_into::<PyTuple>().unwrap();
|
||||
key_sum += tuple.get_item(0).extract::<i32>().unwrap();
|
||||
value_sum += tuple.get_item(1).extract::<i32>().unwrap();
|
||||
for el in dict.items_list(py).iter(py) {
|
||||
let tuple = el.cast_into::<PyTuple>(py).unwrap();
|
||||
key_sum += tuple.get_item(py, 0).extract::<i32>(py).unwrap();
|
||||
value_sum += tuple.get_item(py, 1).extract::<i32>(py).unwrap();
|
||||
}
|
||||
assert_eq!(7 + 8 + 9, key_sum);
|
||||
assert_eq!(32 + 42 + 123, value_sum);
|
||||
}
|
||||
*/
|
||||
|
||||
#[test]
|
||||
fn test_items() {
|
||||
|
|
|
@ -16,29 +16,82 @@
|
|||
// 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};
|
||||
use python::{Python, PythonObject, ToPythonPointer, PythonObjectDowncastError};
|
||||
use conversion::ToPyObject;
|
||||
use objects::PyObject;
|
||||
use err::{PyErr, PyResult};
|
||||
use ffi;
|
||||
|
||||
pub struct PyIterator(PyObject);
|
||||
/// A python iterator object.
|
||||
///
|
||||
/// Unlike other python objects, this class includes a `Python<'p>` token
|
||||
/// so that PyIterator can implement the rust `Iterator` trait.
|
||||
pub struct PyIterator<'p> {
|
||||
py: Python<'p>,
|
||||
iter: PyObject,
|
||||
}
|
||||
|
||||
pyobject_newtype!(PyIterator, PyIter_Check);
|
||||
impl <'p> PyIterator<'p> {
|
||||
/// Constructs a PyIterator from a Python iterator object.
|
||||
pub fn from_object(py: Python<'p>, obj: PyObject) -> Result<PyIterator<'p>, PythonObjectDowncastError<'p>> {
|
||||
if unsafe { ffi::PyIter_Check(obj.as_ptr()) != 0 } {
|
||||
Ok(PyIterator { py: py, iter: obj })
|
||||
} else {
|
||||
Err(PythonObjectDowncastError(py))
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the Python iterator object.
|
||||
#[inline]
|
||||
pub fn as_object(&self) -> &PyObject {
|
||||
&self.iter
|
||||
}
|
||||
|
||||
/// Gets the Python iterator object.
|
||||
#[inline]
|
||||
pub fn into_object(self) -> PyObject {
|
||||
self.iter
|
||||
}
|
||||
}
|
||||
|
||||
impl <'p> Iterator for PyIterator<'p> {
|
||||
type Item = PyResult<PyObject>;
|
||||
|
||||
impl PyIterator {
|
||||
/// Retrieves the next item from an iterator.
|
||||
/// Returns `None` when the iterator is exhausted.
|
||||
pub fn iter_next(&self, py: Python) -> PyResult<Option<PyObject>> {
|
||||
match unsafe { PyObject::from_owned_ptr_opt(py, ffi::PyIter_Next(self.as_ptr())) } {
|
||||
Some(obj) => Ok(Some(obj)),
|
||||
/// If an exception occurs, returns `Some(Err(..))`.
|
||||
/// Further next() calls after an exception occurs are likely
|
||||
/// to repeatedly result in the same exception.
|
||||
fn next(&mut self) -> Option<PyResult<PyObject>> {
|
||||
let py = self.py;
|
||||
match unsafe { PyObject::from_owned_ptr_opt(py, ffi::PyIter_Next(self.iter.as_ptr())) } {
|
||||
Some(obj) => Some(Ok(obj)),
|
||||
None => {
|
||||
if PyErr::occurred(py) {
|
||||
Err(PyErr::fetch(py))
|
||||
Some(Err(PyErr::fetch(py)))
|
||||
} else {
|
||||
Ok(None)
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use python::{Python, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
use objectprotocol::ObjectProtocol;
|
||||
|
||||
#[test]
|
||||
fn vec_iter() {
|
||||
let gil_guard = Python::acquire_gil();
|
||||
let py = gil_guard.python();
|
||||
let obj = vec![10, 20].to_py_object(py).into_object();
|
||||
let mut it = obj.iter(py).unwrap();
|
||||
assert_eq!(10, it.next().unwrap().unwrap().extract(py).unwrap());
|
||||
assert_eq!(20, it.next().unwrap().unwrap().extract(py).unwrap());
|
||||
assert!(it.next().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// 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};
|
||||
use python::{Python, PythonObject, ToPythonPointer, PyClone};
|
||||
use err::{self, PyErr, PyResult};
|
||||
use super::object::PyObject;
|
||||
use ffi::{self, Py_ssize_t};
|
||||
|
@ -75,42 +75,27 @@ impl PyList {
|
|||
let r = unsafe { ffi::PyList_Insert(self.0.as_ptr(), index as Py_ssize_t, item.as_ptr()) };
|
||||
assert!(r == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl <'p> IntoIterator for PyList {
|
||||
type Item = PyObject;
|
||||
type IntoIter = PyListIterator<'p>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> PyListIterator<'p> {
|
||||
PyListIterator { list: self, index: 0 }
|
||||
pub fn iter<'a, 'p>(&'a self, py: Python<'p>) -> PyListIterator<'a, 'p> {
|
||||
PyListIterator { py: py, list: self, index: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'p> IntoIterator for &'a PyList {
|
||||
type Item = PyObject;
|
||||
type IntoIter = PyListIterator<'p>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> PyListIterator<'p> {
|
||||
PyListIterator { list: self.clone(), index: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `impl IntoIterator for &PyList`.
|
||||
TODO pub struct PyListIterator<'p> {
|
||||
list: PyList,
|
||||
/// Used by `PyList::iter()`.
|
||||
pub struct PyListIterator<'a, 'p> {
|
||||
py: Python<'p>,
|
||||
list: &'a PyList,
|
||||
index: usize
|
||||
}
|
||||
|
||||
impl <'p> Iterator for PyListIterator<'p> {
|
||||
impl <'a, 'p> Iterator for PyListIterator<'a, 'p> {
|
||||
type Item = PyObject;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<PyObject> {
|
||||
if self.index < self.list.len() {
|
||||
let item = self.list.get_item(self.index);
|
||||
if self.index < self.list.len(self.py) {
|
||||
let item = self.list.get_item(self.py, self.index);
|
||||
self.index += 1;
|
||||
Some(item)
|
||||
} else {
|
||||
|
@ -121,7 +106,6 @@ impl <'p> Iterator for PyListIterator<'p> {
|
|||
// Note: we cannot implement size_hint because the length of the list
|
||||
// might change during the iteration.
|
||||
}
|
||||
*/
|
||||
|
||||
impl <T> ToPyObject for [T] where T: ToPyObject {
|
||||
type ObjectType = PyList;
|
||||
|
@ -165,7 +149,6 @@ impl <'prepared, T> ExtractPyObject<'prepared> for Vec<T>
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std;
|
||||
use python::{Python, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
use objects::PyList;
|
||||
|
@ -218,36 +201,20 @@ mod test {
|
|||
assert_eq!(2, list.get_item(py, 1).extract::<i32>(py).unwrap());
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
fn test_iter() { TODO
|
||||
fn test_iter() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = vec![2, 3, 5, 7];
|
||||
let list = v.to_py_object(py);
|
||||
let mut idx = 0;
|
||||
for el in list {
|
||||
for el in list.iter(py) {
|
||||
assert_eq!(v[idx], el.extract::<i32>(py).unwrap());
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(idx, v.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v = vec![2, 3, 5, 7];
|
||||
let list = v.to_py_object(py);
|
||||
let mut idx = 0;
|
||||
for el in list.into_iter() {
|
||||
assert_eq!(v[idx], el.extract::<i32>().unwrap());
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(idx, v.len());
|
||||
}
|
||||
*/
|
||||
|
||||
#[test]
|
||||
fn test_extract() {
|
||||
let gil = Python::acquire_gil();
|
||||
|
|
|
@ -27,7 +27,6 @@ pub use self::string::PyBytes as PyString;
|
|||
#[cfg(feature="python3-sys")]
|
||||
pub use self::string::PyUnicode as PyString;
|
||||
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub use self::iterator::PyIterator;
|
||||
pub use self::boolobject::PyBool;
|
||||
pub use self::tuple::{PyTuple, NoArgs};
|
||||
|
@ -160,7 +159,6 @@ mod typeobject;
|
|||
mod module;
|
||||
mod string;
|
||||
mod dict;
|
||||
#[cfg(feature="python27-sys")]
|
||||
mod iterator;
|
||||
mod boolobject;
|
||||
mod tuple;
|
||||
|
|
|
@ -20,7 +20,7 @@ use std::mem;
|
|||
use ffi;
|
||||
use python::{Python, PythonObject, ToPythonPointer, PyClone};
|
||||
use conversion::ToPyObject;
|
||||
use objects::{PyObject, PyList, PyTuple};
|
||||
use objects::{PyObject, PyList, PyTuple, PyIterator};
|
||||
use ffi::Py_ssize_t;
|
||||
use err;
|
||||
use err::{PyErr, PyResult, result_from_owned_ptr, result_cast_from_owned_ptr};
|
||||
|
@ -199,50 +199,11 @@ impl PySequence {
|
|||
result_cast_from_owned_ptr(py, ffi::PySequence_Tuple(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub fn iter<'p>(&self, py: Python<'p>) -> PySequenceIterator<'p> {
|
||||
PySequenceIterator {
|
||||
sequence: self.clone_ref(py),
|
||||
index: 0,
|
||||
py: py
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_iter<'p>(self, py: Python<'p>) -> PySequenceIterator<'p> {
|
||||
PySequenceIterator {
|
||||
sequence: self,
|
||||
index: 0,
|
||||
py: py
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PySequenceIterator<'p> {
|
||||
sequence : PySequence,
|
||||
index : isize,
|
||||
py : Python<'p>
|
||||
}
|
||||
|
||||
impl <'p> Iterator for PySequenceIterator<'p> {
|
||||
// TODO: reconsider error reporting; maybe this should be Item = PyResult<PyObject>?
|
||||
type Item = PyObject;
|
||||
|
||||
fn next(&mut self) -> Option<PyObject> {
|
||||
// can't report any errors in underlying size check so we panic.
|
||||
let len = self.sequence.len(self.py).unwrap();
|
||||
if self.index < len {
|
||||
match self.sequence.get_item(self.py, self.index) {
|
||||
Ok(item) => {
|
||||
self.index += 1;
|
||||
Some(item)
|
||||
},
|
||||
Err(_) => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn iter<'p>(&self, py: Python<'p>) -> PyResult<PyIterator<'p>> {
|
||||
use objectprotocol::ObjectProtocol;
|
||||
self.as_object().iter(py)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,7 +212,7 @@ mod test {
|
|||
use std;
|
||||
use python::{Python, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
use objects::{PySequence, PyList, PyTuple};
|
||||
use objects::{PySequence, PyList, PyTuple, PyIterator};
|
||||
|
||||
#[test]
|
||||
fn test_numbers_are_not_sequences() {
|
||||
|
@ -373,36 +334,20 @@ mod test {
|
|||
assert_eq!(0, seq.count(py, 42i32).unwrap());
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
fn test_seq_iter() { TODO
|
||||
fn test_seq_iter() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
|
||||
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
|
||||
let mut idx = 0;
|
||||
for el in seq {
|
||||
assert_eq!(v[idx], el.extract::<i32>(py).unwrap());
|
||||
for el in seq.iter(py).unwrap() {
|
||||
assert_eq!(v[idx], el.unwrap().extract::<i32>(py).unwrap());
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(idx, v.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_into_iter() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
|
||||
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
|
||||
let mut idx = 0;
|
||||
for el in seq.into_iter() {
|
||||
assert_eq!(v[idx], el.extract::<i32>().unwrap());
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(idx, v.len());
|
||||
}
|
||||
*/
|
||||
|
||||
#[test]
|
||||
fn test_seq_strings() {
|
||||
let gil = Python::acquire_gil();
|
||||
|
@ -426,8 +371,8 @@ mod test {
|
|||
let concat_seq = seq.concat(py, &seq).unwrap().cast_into::<PySequence>(py).unwrap();
|
||||
assert_eq!(6, concat_seq.len(py).unwrap());
|
||||
let concat_v : Vec<i32> = vec![1, 2, 3, 1, 2, 3];
|
||||
for (el, cc) in seq.into_iter(py).zip(concat_v) {
|
||||
assert_eq!(cc, el.extract::<i32>(py).unwrap());
|
||||
for (el, cc) in seq.iter(py).unwrap().zip(concat_v) {
|
||||
assert_eq!(cc, el.unwrap().extract::<i32>(py).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,8 +399,8 @@ mod test {
|
|||
let repeat_seq = seq.repeat(py, 3).unwrap().cast_into::<PySequence>(py).unwrap();
|
||||
assert_eq!(6, repeat_seq.len(py).unwrap());
|
||||
let repeated = vec!["foo", "bar", "foo", "bar", "foo", "bar"];
|
||||
for (el, rpt) in seq.into_iter(py).zip(repeated.iter()) {
|
||||
assert_eq!(*rpt, el.extract::<String>(py).unwrap());
|
||||
for (el, rpt) in seq.iter(py).unwrap().zip(repeated.iter()) {
|
||||
assert_eq!(*rpt, el.unwrap().extract::<String>(py).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,45 +84,52 @@ impl PyTuple {
|
|||
self.len()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO impl Index for PyTuple
|
||||
|
||||
/*
|
||||
impl IntoIterator for PyTuple { TODO
|
||||
type Item = PyObject;
|
||||
type IntoIter = PyTupleIterator;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> PyTupleIterator {
|
||||
PyTupleIterator { index: 0, end: self.len(), tuple: self }
|
||||
pub fn iter<'a, 'p>(&'a self, py: Python<'p>) -> PyTupleIterator<'a, 'p> {
|
||||
PyTupleIterator {
|
||||
py: py,
|
||||
tuple: self,
|
||||
index: 0,
|
||||
end: self.len()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Index<usize> for PyTuple {
|
||||
type Output = PyObject;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &PyObject {
|
||||
&self.as_slice()[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a> IntoIterator for &'a PyTuple {
|
||||
type Item = PyObject<'p>;
|
||||
type IntoIter = PyTupleIterator<'p>;
|
||||
type Item = &'a PyObject;
|
||||
type IntoIter = slice::Iter<'a, PyObject>;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> PyTupleIterator<'p> {
|
||||
PyTupleIterator { index: 0, end: self.len(), tuple: self.clone() }
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.as_slice().iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `impl IntoIterator for &PyTuple`.
|
||||
pub struct PyTupleIterator<'p> {
|
||||
tuple: PyTuple<'p>,
|
||||
/// Used by `PyTuple::iter()`.
|
||||
pub struct PyTupleIterator<'a, 'p> {
|
||||
py: Python<'p>,
|
||||
tuple: &'a PyTuple,
|
||||
index: usize,
|
||||
end: usize
|
||||
}
|
||||
|
||||
impl <'p> Iterator for PyTupleIterator<'p> {
|
||||
type Item = PyObject<'p>;
|
||||
impl <'a, 'p> Iterator for PyTupleIterator<'a, 'p> {
|
||||
type Item = PyObject;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<PyObject<'p>> {
|
||||
fn next(&mut self) -> Option<PyObject> {
|
||||
if self.index < self.end {
|
||||
let item = self.tuple.get_item(self.index);
|
||||
let item = self.tuple.get_item(self.py, self.index);
|
||||
self.index += 1;
|
||||
Some(item)
|
||||
} else {
|
||||
|
@ -136,13 +143,12 @@ impl <'p> Iterator for PyTupleIterator<'p> {
|
|||
}
|
||||
}
|
||||
|
||||
impl <'p> ExactSizeIterator for PyTupleIterator<'p> {
|
||||
impl <'a, 'p> ExactSizeIterator for PyTupleIterator<'a, 'p> {
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
self.end - self.index
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr {
|
||||
let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len());
|
||||
|
@ -232,3 +238,19 @@ extract!(obj to NoArgs; py => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use python::{Python, PythonObject};
|
||||
use conversion::ToPyObject;
|
||||
|
||||
#[test]
|
||||
fn test_len() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let tuple = (1, 2, 3).to_py_object(py);
|
||||
assert_eq!(3, tuple.len());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue