restore sequence and iterator objects

This commit is contained in:
Nikolay Kim 2017-05-29 22:59:03 -07:00
parent 61b8bd0695
commit 86a8dfec0c
13 changed files with 351 additions and 314 deletions

View File

@ -133,6 +133,16 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) ->
}
}
impl _pyo3::python::ToPythonPointer for #cls {
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
unsafe {
{self as *const _ as *mut u8}.offset(-offset) as *mut ffi::PyObject
}
}
}
impl _pyo3::class::PyCustomObject for #cls {
}

View File

@ -33,8 +33,6 @@ pub static NO_PY_METHODS: &'static [PyMethodDefType] = &[];
use ffi;
use typeob::PyTypeInfo;
use python::ToPythonPointer;
use token::PythonObjectWithToken;
#[derive(Debug)]
pub enum CompareOp {
@ -47,13 +45,3 @@ pub enum CompareOp {
}
pub trait PyCustomObject : PyTypeInfo + Sized {}
impl<'p, T> ToPythonPointer for T where T: PyCustomObject + PythonObjectWithToken {
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
let offset = <T as PyTypeInfo>::offset();
unsafe {
{self as *const _ as *mut u8}.offset(-offset) as *mut ffi::PyObject
}
}
}

View File

@ -2,10 +2,9 @@
use pyptr::PyPtr;
use token::PyObjectMarker;
use typeob::PyTypeInfo;
use objects::PyObject;
pub trait PyBaseObject : PyTypeInfo + Sized {}
pub trait PyBaseObject : Sized {}
pub trait PyNativeObject<'p> : PyBaseObject {

View File

@ -6,9 +6,10 @@ use std::fmt;
use std::cmp::Ordering;
use ffi;
use libc;
use ppptr::pptr;
use pyptr::{Py, PyPtr};
use python::{Python, PyDowncastInto, ToPythonPointer};
use objects::{PyObject, PyDict, PyString};
use objects::{PyObject, PyDict, PyString, PyIterator};
use token::PythonObjectWithGilToken;
use conversion::{ToPyObject, ToPyTuple};
use typeob::PyTypeInfo;
@ -115,10 +116,10 @@ pub trait ObjectProtocol<'p> {
/// This is equivalent to the Python expression 'del self[key]'.
fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject;
// /// 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.
// fn iter<'a>(&'a self) -> PyResult<Py<'p, ::objects::PyIterator<'a>>>;
/// 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.
fn iter(&self) -> PyResult<PyIterator<'p>>;
fn get_refcnt(&self) -> isize;
}
@ -366,13 +367,17 @@ impl<'p, T> ObjectProtocol<'p> for T where T: PythonObjectWithGilToken<'p> + ToP
})
}
// /// 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.
//#[inline]
//pub fn iter<'a>(&'a self) -> PyResult<Py<'p, ::objects::PyIterator<'a>>> {
// Py::from_owned_ptr_or_err(self.py(), ffi::PyObject_GetIter(self.as_ptr()))
//}
/// 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.
#[inline]
fn iter(&self) -> PyResult<PyIterator<'p>> {
unsafe {
let ptr = pptr::from_owned_ptr_or_err(
self.gil(), ffi::PyObject_GetIter(self.as_ptr()))?;
PyIterator::from_object(self.gil(), ptr).map_err(|e| e.into())
}
}
fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.as_ptr()) }

View File

@ -78,7 +78,7 @@ impl<'p> PyByteArray<'p> {
mod test {
use ::ToPyObject;
use exc;
use python::{Python, ToPythonPointer};
use python::Python;
use typeob::PyTypeObject;
use objects::PyByteArray;
@ -101,7 +101,6 @@ mod test {
assert_eq!(20, bytearray.len());
let none = py.None();
println!("NONE: {:?} {}", none.as_ptr(), none.get_refcnt());
if let Err(mut err) = PyByteArray::from(none.as_object(py)) {
assert!(exc::TypeError::type_object(py).is_instance(&err.instance(py)))
} else {

View File

@ -5,10 +5,10 @@
use ::pptr;
use ffi;
use pyptr::PyPtr;
use python::{Python, ToPythonPointer};
use python::{Python, ToPythonPointer, PyDowncastInto};
use conversion::{ToPyObject, IntoPyObject};
use objects::PyObject;
use token::{PyObjectMarker, PythonObjectWithGilToken}; //, PyList};
use objects::{PyObject, PyList};
use token::{PyObjectMarker, PythonObjectWithGilToken};
use err::{self, PyResult, PyErr};
use std::{mem, collections, hash, cmp};
@ -98,11 +98,12 @@ impl<'p> PyDict<'p> {
// List of dict items.
// This is equivalent to the python expression `list(dict.items())`.
//pub fn items_list(&self) -> Py<PyList> {
// unsafe {
// Py::from_owned_ptr_or_panic(self.py(), ffi::PyDict_Items(self.as_ptr()))
// }
//}
pub fn items_list(&self) -> PyList<'p> {
unsafe {
PyList::downcast_from_owned_ptr(
self.gil(), ffi::PyDict_Items(self.as_ptr())).unwrap()
}
}
/// Returns the list of (key, value) pairs in this dictionary.
pub fn items(&self) -> Vec<(PyObject<'p>, PyObject<'p>)> {
@ -153,9 +154,9 @@ impl <K, V> ToPyObject for collections::BTreeMap<K, V>
#[cfg(test)]
mod test {
use std::collections::{BTreeMap, HashMap};
use python::{Python};
use python::{Python, PyDowncastInto};
use conversion::ToPyObject;
use objects::{PyDict}; //, PyTuple};
use objects::{PyDict, PyTuple};
use ::PyDowncastFrom;
@ -251,7 +252,7 @@ mod test {
assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated!
}
/*#[test]
#[test]
fn test_items_list() {
let gil = Python::acquire_gil();
let py = gil.python();
@ -259,18 +260,18 @@ mod test {
v.insert(7, 32);
v.insert(8, 42);
v.insert(9, 123);
let dict = PyDict::downcast_from(py, v.to_py_object(py)).unwrap();
let dict = PyDict::downcast_into(py, v.to_object(py)).unwrap();
// 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).iter(py) {
for el in dict.items_list().iter() {
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();
key_sum += tuple.get_item(0).extract::<i32>().unwrap();
value_sum += tuple.get_item(1).extract::<i32>().unwrap();
}
assert_eq!(7 + 8 + 9, key_sum);
assert_eq!(32 + 42 + 123, value_sum);
}*/
}
#[test]
fn test_items() {

View File

@ -2,58 +2,52 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use python::{Python, PythonObjectDowncastError};
use objects::PyObject;
use err::{PyErr, PyResult};
use ffi;
use ppptr::pptr;
use python::{Python, ToPythonPointer, IntoPythonPointer};
use objects::PyObject;
use err::{PyErr, PyResult, PyDowncastError};
/// 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,
}
pub struct PyIterator<'p>(pptr<'p>);
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, None))
pub fn from_object<T>(py: Python<'p>, obj: T)
-> Result<PyIterator<'p>, PyDowncastError<'p>>
where T: IntoPythonPointer
{
unsafe {
let ptr = obj.into_ptr();
if ffi::PyIter_Check(ptr) != 0 {
Ok(PyIterator(pptr::from_borrowed_ptr(py, ptr)))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError(py, None))
}
}
}
/// 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>;
type Item = PyResult<PyObject<'p>>;
/// Retrieves the next item from an iterator.
/// Returns `None` when the iterator is exhausted.
/// 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())) } {
fn next(&mut self) -> Option<PyResult<PyObject<'p>>> {
match unsafe { PyObject::from_owned_ptr_or_opt(
self.0.token(), ffi::PyIter_Next(self.0.as_ptr())) } {
Some(obj) => Some(Ok(obj)),
None => {
if PyErr::occurred(py) {
Some(Err(PyErr::fetch(py)))
if PyErr::occurred(self.0.token()) {
Some(Err(PyErr::fetch(self.0.token())))
} else {
None
}
@ -64,7 +58,7 @@ impl <'p> Iterator for PyIterator<'p> {
#[cfg(test)]
mod tests {
use python::{Python, PythonObject};
use python::{Python};
use conversion::ToPyObject;
use objectprotocol::ObjectProtocol;
@ -72,11 +66,10 @@ mod tests {
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());
let obj = vec![10, 20].to_object(py).into_object(py);
let mut it = obj.iter().unwrap();
assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap());
assert_eq!(20, it.next().unwrap().unwrap().extract().unwrap());
assert!(it.next().is_none());
}
}

View File

@ -3,10 +3,12 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use ::pptr;
use pyptr::{Py, PyPtr};
use python::{Python, ToPythonPointer, IntoPythonPointer, PythonToken, PythonObjectWithToken};
use objects::PyObject;
use err::{self, PyResult};
use ffi::{self, Py_ssize_t};
use pyptr::PyPtr;
use python::{Python, ToPythonPointer, IntoPythonPointer};
use objects::PyObject;
use token::{PyObjectMarker, PythonObjectWithGilToken};
use conversion::{ToPyObject, IntoPyObject};
/// Represents a Python `list`.
@ -38,30 +40,35 @@ impl<'p> PyList<'p> {
/// Gets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn get_item(&self, index: usize) -> &PyObject {
// TODO: do we really want to panic here?
assert!(index < self.len());
pub fn get_item(&self, index: isize) -> PyObject<'p> {
unsafe {
let ptr = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t);
self.py_token().from_owned(ptr)
PyObject::from_borrowed_ptr(
self.gil(), ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t))
}
}
/// Sets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn set_item(&self, index: usize, item: Py<'p, PyObject>) {
let r = unsafe { ffi::PyList_SetItem(
self.as_ptr(), index as Py_ssize_t, item.into_ptr()) };
assert!(r == 0);
pub fn set_item<I>(&self, index: isize, item: I) -> PyResult<()>
where I: ToPyObject
{
item.with_borrowed_ptr(self.gil(), |item| unsafe {
err::error_on_minusone(
self.gil(), ffi::PyList_SetItem(self.as_ptr(), index, item))
})
}
/// Inserts an item at the specified index.
///
/// Panics if the index is out of range.
pub fn insert_item(&self, index: usize, item: Py<'p, PyObject>) {
let r = unsafe { ffi::PyList_Insert(self.as_ptr(), index as Py_ssize_t, item.as_ptr()) };
assert!(r == 0);
pub fn insert_item<I>(&self, index: isize, item: I) -> PyResult<()>
where I: ToPyObject
{
item.with_borrowed_ptr(self.gil(), |item| unsafe {
err::error_on_minusone(
self.gil(), ffi::PyList_Insert(self.as_ptr(), index, item))
})
}
#[inline]
@ -73,15 +80,15 @@ impl<'p> PyList<'p> {
/// Used by `PyList::iter()`.
pub struct PyListIterator<'p> {
list: &'p PyList<'p>,
index: usize
index: isize
}
impl <'p> Iterator for PyListIterator<'p> {
type Item = Py<'p, PyObject>;
type Item = PyObject<'p>;
#[inline]
fn next(&mut self) -> Option<&'p PyObject> {
if self.index < self.list.len() {
fn next(&mut self) -> Option<PyObject<'p>> {
if self.index < self.list.len() as isize {
let item = self.list.get_item(self.index);
self.index += 1;
Some(item)
@ -96,7 +103,7 @@ impl <'p> Iterator for PyListIterator<'p> {
impl <T> ToPyObject for [T] where T: ToPyObject {
fn to_object(&self, py: Python) -> PyPtr<PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
unsafe {
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
for (i, e) in self.iter().enumerate() {
@ -110,7 +117,7 @@ impl <T> ToPyObject for [T] where T: ToPyObject {
impl <T> ToPyObject for Vec<T> where T: ToPyObject {
fn to_object<'p>(&self, py: Python<'p>) -> PyPtr<PyObject> {
fn to_object(&self, py: Python) -> PyPtr<PyObjectMarker> {
self.as_slice().to_object(py)
}
@ -118,7 +125,7 @@ impl <T> ToPyObject for Vec<T> where T: ToPyObject {
impl <T> IntoPyObject for Vec<T> where T: IntoPyObject {
fn into_object(self, py: Python) -> PyPtr<PyObject> {
fn into_object(self, py: Python) -> PyPtr<PyObjectMarker> {
unsafe {
let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
for (i, e) in self.into_iter().enumerate() {
@ -132,8 +139,8 @@ impl <T> IntoPyObject for Vec<T> where T: IntoPyObject {
#[cfg(test)]
mod test {
use python::{Python, PythonObjectWithCheckedDowncast};
use conversion::ToPyObject;
use python::{Python, PyDowncastInto};
use conversion::{ToPyObject, IntoPyObject};
use objects::PyList;
#[test]
@ -141,8 +148,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![1,2,3,4];
let list = PyList::downcast_from(py, v.to_object(py)).unwrap();
assert_eq!(4, list.len(py));
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
assert_eq!(4, list.len());
}
#[test]
@ -150,11 +157,11 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_from(py, v.to_py_object(py)).unwrap();
assert_eq!(2, list.get_item(py, 0).extract::<i32>(py).unwrap());
assert_eq!(3, list.get_item(py, 1).extract::<i32>(py).unwrap());
assert_eq!(5, list.get_item(py, 2).extract::<i32>(py).unwrap());
assert_eq!(7, list.get_item(py, 3).extract::<i32>(py).unwrap());
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(3, list.get_item(1).extract::<i32>().unwrap());
assert_eq!(5, list.get_item(2).extract::<i32>().unwrap());
assert_eq!(7, list.get_item(3).extract::<i32>().unwrap());
}
#[test]
@ -162,11 +169,11 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_from(py, v.to_py_object(py)).unwrap();
let val = 42i32.to_py_object(py).into_object();
assert_eq!(2, list.get_item(py, 0).extract::<i32>(py).unwrap());
list.set_item(py, 0, val);
assert_eq!(42, list.get_item(py, 0).extract::<i32>(py).unwrap());
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let val = 42i32.to_object(py).into_object(py);
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
list.set_item(0, val).unwrap();
assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
}
#[test]
@ -174,14 +181,14 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_from(py, v.to_py_object(py)).unwrap();
let val = 42i32.to_py_object(py).into_object();
assert_eq!(4, list.len(py));
assert_eq!(2, list.get_item(py, 0).extract::<i32>(py).unwrap());
list.insert_item(py, 0, val);
assert_eq!(5, list.len(py));
assert_eq!(42, list.get_item(py, 0).extract::<i32>(py).unwrap());
assert_eq!(2, list.get_item(py, 1).extract::<i32>(py).unwrap());
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let val = 42i32.to_object(py).into_object(py);
assert_eq!(4, list.len());
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
list.insert_item(0, val).unwrap();
assert_eq!(5, list.len());
assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(2, list.get_item(1).extract::<i32>().unwrap());
}
#[test]
@ -189,10 +196,10 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_from(py, v.to_py_object(py)).unwrap();
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let mut idx = 0;
for el in list.iter(py) {
assert_eq!(v[idx], el.extract::<i32>(py).unwrap());
for el in list.iter() {
assert_eq!(v[idx], el.extract::<i32>().unwrap());
idx += 1;
}
assert_eq!(idx, v.len());
@ -203,8 +210,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_from(py, v.to_py_object(py)).unwrap();
let v2 = list.into_object().extract::<Vec<i32>>(py).unwrap();
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let v2 = list.into_object(py).into_object(py).extract::<Vec<i32>>().unwrap();
assert_eq!(v, v2);
}
}

View File

@ -4,21 +4,21 @@ pub use self::object::PyObject;
pub use self::typeobject::PyType;
pub use self::module::PyModule;
pub use self::string::{PyBytes, PyString, PyStringData};
//pub use self::iterator::PyIterator;
pub use self::iterator::PyIterator;
pub use self::boolobject::PyBool;
pub use self::bytearray::PyByteArray;
pub use self::tuple::{PyTuple, NoArgs};
pub use self::dict::PyDict;
//pub use self::list::PyList;
pub use self::list::PyList;
pub use self::num::{PyLong, PyFloat};
//pub use self::sequence::PySequence;
pub use self::sequence::PySequence;
pub use self::slice::PySlice;
//pub use self::set::{PySet, PyFrozenSet};
#[macro_export]
macro_rules! pyobject_nativetype(
($name: ident, $checkfunction: ident, $typeobject: ident) => (
($name: ident, $checkfunction: ident, $typeobject: ident) => {
impl<'p> $crate::typeob::PyTypeInfo for $name<'p> {
type Type = ();
@ -43,6 +43,11 @@ macro_rules! pyobject_nativetype(
}
}
pyobject_nativetype!($name, $checkfunction);
};
($name: ident, $checkfunction: ident) => (
impl<'p> $crate::native::PyBaseObject for $name<'p> {}
impl<'p> $crate::native::PyNativeObject<'p> for $name<'p> {
@ -80,22 +85,32 @@ macro_rules! pyobject_nativetype(
impl<'p> $crate::python::PyDowncastInto<'p> for $name<'p>
{
fn downcast_into(py: $crate::Python<'p>, ob: $crate::PyObject)
-> Result<$name<'p>, $crate::PyDowncastError<'p>>
fn downcast_into<I>(py: $crate::Python<'p>, ob: I)
-> Result<Self, $crate::PyDowncastError<'p>>
where I: $crate::ToPythonPointer + $crate::IntoPythonPointer
{
match $crate::pptr::cast_from_owned_ptr::<$name>(py, ob.as_ptr()) {
Ok(ptr) => {
$crate::std::mem::forget(ob);
Ok($name(ptr))
},
Err(e) => Err(e)
unsafe{
let ptr = ob.into_ptr();
if ffi::$checkfunction(ptr) != 0 {
Ok($name(pptr::from_owned_ptr(py, ptr)))
} else {
$crate::ffi::Py_DECREF(ptr);
Err($crate::PyDowncastError(py, None))
}
}
}
fn downcast_from_owned_ptr(py: $crate::Python<'p>, ptr: *mut $crate::ffi::PyObject)
-> Result<$name<'p>, $crate::PyDowncastError<'p>>
{
Ok($name($crate::pptr::cast_from_owned_ptr::<$name>(py, ptr)?))
unsafe{
if ffi::$checkfunction(ptr) != 0 {
Ok($name(pptr::from_owned_ptr(py, ptr)))
} else {
$crate::ffi::Py_DECREF(ptr);
Err($crate::PyDowncastError(py, None))
}
}
}
}
@ -124,8 +139,13 @@ macro_rules! pyobject_nativetype(
{
use $crate::token::PythonObjectWithGilToken;
Ok($name(
$crate::pptr::cast_from_borrowed_ptr::<$name>(py.gil(), py.as_ptr())?))
unsafe {
if ffi::$checkfunction(py.as_ptr()) != 0 {
Ok( $name($crate::pptr::from_borrowed_ptr(py.gil(), py.as_ptr())) )
} else {
Err(::PyDowncastError(py.gil(), None).into())
}
}
}
}
@ -222,13 +242,13 @@ mod typeobject;
mod module;
mod string;
mod dict;
//mod iterator;
mod iterator;
mod boolobject;
mod bytearray;
mod tuple;
//mod list;
mod list;
mod num;
//mod sequence;
mod sequence;
mod slice;
// mod set;
mod object;

View File

@ -3,26 +3,31 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use ffi;
use python::{Python, PythonObject, ToPythonPointer, PyDrop};
use ppptr::pptr;
use python::{ToPythonPointer, PyDowncastFrom, PyDowncastInto};
use conversion::{FromPyObject, ToPyObject};
use objects::{PyObject, PyList, PyTuple, PyIterator};
use objects::{PyObject, PyList, PyTuple};
use ffi::Py_ssize_t;
use err;
use err::{PyErr, PyResult, result_from_owned_ptr, result_cast_from_owned_ptr};
use buffer;
use err::{PyErr, PyResult};
// use buffer;
use token::PythonObjectWithGilToken;
use objectprotocol::ObjectProtocol;
/// Represents a reference to a python object supporting the sequence protocol.
pub struct PySequence(PyObject);
pub struct PySequence<'p>(pptr<'p>);
pyobject_newtype!(PySequence, PySequence_Check);
pyobject_nativetype!(PySequence, PySequence_Check);
impl PySequence {
impl<'p> PySequence<'p> {
/// Returns the number of objects in sequence. This is equivalent to Python `len()`.
#[inline]
pub fn len(&self, py: Python) -> PyResult<isize> {
pub fn len(&self) -> PyResult<isize> {
let v = unsafe { ffi::PySequence_Size(self.0.as_ptr()) };
if v == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.gil()))
} else {
Ok(v as isize)
}
@ -30,9 +35,11 @@ impl PySequence {
/// Return the concatenation of o1 and o2. Equivalent to python `o1 + o2`
#[inline]
pub fn concat(&self, py: Python, other: &PySequence) -> PyResult<PyObject> {
pub fn concat(&self, other: &PySequence) -> PyResult<PySequence<'p>> {
unsafe {
err::result_from_owned_ptr(py, ffi::PySequence_Concat(self.as_ptr(), other.as_ptr()))
Ok(PySequence(pptr::from_owned_ptr_or_err(
self.gil(),
ffi::PySequence_Concat(self.as_ptr(), other.as_ptr()))?))
}
}
@ -40,17 +47,21 @@ impl PySequence {
/// Equivalent to python `o * count`
/// NB: Python accepts negative counts; it returns an empty Sequence.
#[inline]
pub fn repeat(&self, py: Python, count: isize) -> PyResult<PyObject> {
pub fn repeat(&self, count: isize) -> PyResult<PySequence<'p>> {
unsafe {
err::result_from_owned_ptr(py, ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))
Ok(PySequence(pptr::from_owned_ptr_or_err(
self.gil(),
ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))?))
}
}
/// Return the concatenation of o1 and o2 on success. Equivalent to python `o1 += o2`
#[inline]
pub fn in_place_concat(&self, py: Python, other: &PySequence) -> PyResult<PyObject> {
pub fn in_place_concat(&self, other: &PySequence) -> PyResult<PySequence<'p>> {
unsafe {
result_from_owned_ptr(py, ffi::PySequence_InPlaceConcat(self.as_ptr(), other.as_ptr()))
Ok(PySequence(pptr::from_owned_ptr_or_err(
self.0.token(),
ffi::PySequence_InPlaceConcat(self.0.as_ptr(), other.as_ptr()))?))
}
}
@ -58,28 +69,30 @@ impl PySequence {
/// Equivalent to python `o *= count`
/// NB: Python accepts negative counts; it empties the Sequence.
#[inline]
pub fn in_place_repeat(&self, py: Python, count: isize) -> PyResult<PyObject> {
pub fn in_place_repeat(&self, count: isize) -> PyResult<PySequence<'p>> {
unsafe {
result_from_owned_ptr(py,
ffi::PySequence_InPlaceRepeat(self.as_ptr(), count as Py_ssize_t))
Ok(PySequence(pptr::from_owned_ptr_or_err(
self.0.token(),
ffi::PySequence_InPlaceRepeat(self.as_ptr(), count as Py_ssize_t))?))
}
}
/// Return the ith element of the Sequence. Equivalent to python `o[index]`
#[inline]
pub fn get_item(&self, py: Python, index: isize) -> PyResult<PyObject> {
pub fn get_item(&self, index: isize) -> PyResult<PyObject<'p>> {
unsafe {
result_from_owned_ptr(py,
ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t))
PyObject::from_owned_ptr_or_err(
self.0.token(), ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t))
}
}
/// Return the slice of sequence object o between begin and end.
/// This is the equivalent of the Python expression `o[begin:end]`
#[inline]
pub fn get_slice(&self, py: Python, begin : isize, end : isize) -> PyResult<PyObject> {
pub fn get_slice(&self, begin: isize, end: isize) -> PyResult<PyObject> {
unsafe {
result_from_owned_ptr(py,
PyObject::from_owned_ptr_or_err(
self.0.token(),
ffi::PySequence_GetSlice(self.as_ptr(), begin as Py_ssize_t, end as Py_ssize_t))
}
}
@ -87,9 +100,9 @@ impl PySequence {
/// Assign object v to the ith element of o.
/// Equivalent to Python statement `o[i] = v`
#[inline]
pub fn set_item(&self, py: Python, i: isize, v: &PyObject) -> PyResult<()> {
pub fn set_item(&self, i: isize, v: &PyObject) -> PyResult<()> {
unsafe {
err::error_on_minusone(py,
err::error_on_minusone(self.0.token(),
ffi::PySequence_SetItem(self.as_ptr(), i as Py_ssize_t, v.as_ptr()))
}
}
@ -97,9 +110,9 @@ impl PySequence {
/// Delete the ith element of object o.
/// Python statement `del o[i]`
#[inline]
pub fn del_item(&self, py: Python, i: isize) -> PyResult<()> {
pub fn del_item(&self, i: isize) -> PyResult<()> {
unsafe {
err::error_on_minusone(py,
err::error_on_minusone(self.0.token(),
ffi::PySequence_DelItem(self.as_ptr(), i as Py_ssize_t))
}
}
@ -107,19 +120,22 @@ impl PySequence {
/// Assign the sequence object v to the slice in sequence object o from i1 to i2.
/// This is the equivalent of the Python statement `o[i1:i2] = v`
#[inline]
pub fn set_slice(&self, py: Python, i1: isize, i2: isize, v: &PyObject) -> PyResult<()> {
pub fn set_slice(&self, i1: isize, i2: isize, v: &PyObject) -> PyResult<()> {
unsafe {
err::error_on_minusone(py,
ffi::PySequence_SetSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t, v.as_ptr()))
err::error_on_minusone(
self.0.token(),
ffi::PySequence_SetSlice(
self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t, v.as_ptr()))
}
}
/// Delete the slice in sequence object o from i1 to i2.
/// equivalent of the Python statement `del o[i1:i2]`
#[inline]
pub fn del_slice(&self, py: Python, i1: isize, i2: isize) -> PyResult<()> {
pub fn del_slice(&self, i1: isize, i2: isize) -> PyResult<()> {
unsafe {
err::error_on_minusone(py,
err::error_on_minusone(
self.0.token(),
ffi::PySequence_DelSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t))
}
}
@ -127,14 +143,14 @@ impl PySequence {
/// Return the number of occurrences of value in o, that is, return the number of keys for
/// which `o[key] == value`
#[inline]
pub fn count<V>(&self, py: Python, value: V) -> PyResult<usize>
pub fn count<V>(&self, value: V) -> PyResult<usize>
where V: ToPyObject
{
let r = value.with_borrowed_ptr(py, |ptr| unsafe {
let r = value.with_borrowed_ptr(self.0.token(), |ptr| unsafe {
ffi::PySequence_Count(self.as_ptr(), ptr)
});
if r == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.gil()))
} else {
Ok(r as usize)
}
@ -142,30 +158,30 @@ impl PySequence {
/// Determine if o contains value. this is equivalent to the Python expression `value in o`
#[inline]
pub fn contains<V>(&self, py: Python, value: V) -> PyResult<bool>
pub fn contains<V>(&self, value: V) -> PyResult<bool>
where V: ToPyObject
{
let r = value.with_borrowed_ptr(py, |ptr| unsafe {
let r = value.with_borrowed_ptr(self.0.token(), |ptr| unsafe {
ffi::PySequence_Contains(self.as_ptr(), ptr)
});
match r {
0 => Ok(false),
1 => Ok(true),
_ => Err(PyErr::fetch(py))
_ => Err(PyErr::fetch(self.gil()))
}
}
/// Return the first index i for which o[i] == value.
/// This is equivalent to the Python expression `o.index(value)`
#[inline]
pub fn index<V>(&self, py: Python, value: V) -> PyResult<usize>
pub fn index<V>(&self, value: V) -> PyResult<usize>
where V: ToPyObject
{
let r = value.with_borrowed_ptr(py, |ptr| unsafe {
let r = value.with_borrowed_ptr(self.0.token(), |ptr| unsafe {
ffi::PySequence_Index(self.as_ptr(), ptr)
});
if r == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.gil()))
} else {
Ok(r as usize)
}
@ -173,46 +189,33 @@ impl PySequence {
/// Return a fresh list based on the Sequence.
#[inline]
pub fn list(&self, py: Python) -> PyResult<PyList> {
pub fn list(&self) -> PyResult<PyList<'p>> {
unsafe {
result_cast_from_owned_ptr(py, ffi::PySequence_List(self.as_ptr()))
Ok(PyList::downcast_from_owned_ptr(
self.0.token(), ffi::PySequence_List(self.as_ptr()))?)
}
}
/// Return a fresh tuple based on the Sequence.
#[inline]
pub fn tuple(&self, py: Python) -> PyResult<PyTuple> {
pub fn tuple(&self) -> PyResult<PyTuple> {
unsafe {
result_cast_from_owned_ptr(py, ffi::PySequence_Tuple(self.as_ptr()))
Ok(PyTuple::downcast_from_owned_ptr(
self.0.token(), ffi::PySequence_Tuple(self.as_ptr()))?)
}
}
#[inline]
pub fn iter<'p>(&self, py: Python<'p>) -> PyResult<PyIterator<'p>> {
use objectprotocol::ObjectProtocol;
self.as_object().iter(py)
}
}
#[cfg(not(feature="nightly"))]
impl <'source, T> FromPyObject<'source> for Vec<T>
impl<'source, T> FromPyObject<'source> for Vec<T>
where for<'a> T: FromPyObject<'a>
{
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
extract_sequence(py, obj)
default fn extract(obj: &'source PyObject<'source>) -> PyResult<Self> {
extract_sequence(obj)
}
}
#[cfg(feature="nightly")]
impl <'source, T> FromPyObject<'source> for Vec<T>
where for<'a> T: FromPyObject<'a>
{
default fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
extract_sequence(py, obj)
}
}
#[cfg(feature="nightly")]
/*#[cfg(feature="nightly")]
impl <'source, T> FromPyObject<'source> for Vec<T>
where for<'a> T: FromPyObject<'a> + buffer::Element + Copy
{
@ -230,34 +233,33 @@ impl <'source, T> FromPyObject<'source> for Vec<T>
// fall back to sequence protocol
extract_sequence(py, obj)
}
}
}*/
fn extract_sequence<T>(py: Python, obj: &PyObject) -> PyResult<Vec<T>>
fn extract_sequence<T>(obj: &PyObject) -> PyResult<Vec<T>>
where for<'a> T: FromPyObject<'a>
{
let seq = try!(obj.cast_as::<PySequence>(py));
let seq = PySequence::downcast_from(obj)?;
let mut v = Vec::new();
for item in try!(seq.iter(py)) {
for item in try!(seq.iter()) {
let item = try!(item);
v.push(try!(T::extract(py, &item)));
item.release_ref(py);
v.push(try!(T::extract(&item)));
}
Ok(v)
}
#[cfg(test)]
mod test {
use std;
use python::{Python, PythonObject};
use python::{Python, PyDowncastInto};
use conversion::ToPyObject;
use objects::{PySequence, PyList, PyTuple, PyIterator};
use objects::{PySequence};
use objectprotocol::ObjectProtocol;
#[test]
fn test_numbers_are_not_sequences() {
let gil = Python::acquire_gil();
let py = gil.python();
let v = 42i32;
assert!(v.to_py_object(py).into_object().cast_into::<PySequence>(py).is_err());
assert!(v.to_object(py).into_object(py).cast_into::<PySequence>(py).is_err());
}
#[test]
@ -265,18 +267,18 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "London Calling";
assert!(v.to_py_object(py).into_object().cast_into::<PySequence>(py).is_ok());
assert!(v.to_object(py).into_object(py).cast_into::<PySequence>(py).is_ok());
}
#[test]
fn test_seq_empty() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert_eq!(0, seq.len(py).unwrap());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(0, seq.len().unwrap());
let needle = 7i32.to_py_object(py).into_object();
assert_eq!(false, seq.contains(py, &needle).unwrap());
let needle = 7i32.to_object(py).into_object(py);
assert_eq!(false, seq.contains(&needle).unwrap());
}
#[test]
@ -284,17 +286,17 @@ mod test {
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();
assert_eq!(6, seq.len(py).unwrap());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(6, seq.len().unwrap());
let bad_needle = 7i32.to_py_object(py).into_object();
assert_eq!(false, seq.contains(py, &bad_needle).unwrap());
let bad_needle = 7i32.to_object(py).into_object(py);
assert_eq!(false, seq.contains(&bad_needle).unwrap());
let good_needle = 8i32.to_py_object(py).into_object();
assert_eq!(true, seq.contains(py, &good_needle).unwrap());
let good_needle = 8i32.to_object(py).into_object(py);
assert_eq!(true, seq.contains(&good_needle).unwrap());
let type_coerced_needle = 8f32.to_py_object(py).into_object();
assert_eq!(true, seq.contains(py, &type_coerced_needle).unwrap());
let type_coerced_needle = 8f32.to_object(py).into_object(py);
assert_eq!(true, seq.contains(&type_coerced_needle).unwrap());
}
#[test]
@ -302,19 +304,19 @@ mod test {
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();
assert_eq!(1, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert_eq!(1, seq.get_item(py, 1).unwrap().extract::<i32>(py).unwrap());
assert_eq!(2, seq.get_item(py, 2).unwrap().extract::<i32>(py).unwrap());
assert_eq!(3, seq.get_item(py, 3).unwrap().extract::<i32>(py).unwrap());
assert_eq!(5, seq.get_item(py, 4).unwrap().extract::<i32>(py).unwrap());
assert_eq!(8, seq.get_item(py, 5).unwrap().extract::<i32>(py).unwrap());
assert_eq!(8, seq.get_item(py, -1).unwrap().extract::<i32>(py).unwrap());
assert_eq!(5, seq.get_item(py, -2).unwrap().extract::<i32>(py).unwrap());
assert_eq!(3, seq.get_item(py, -3).unwrap().extract::<i32>(py).unwrap());
assert_eq!(2, seq.get_item(py, -4).unwrap().extract::<i32>(py).unwrap());
assert_eq!(1, seq.get_item(py, -5).unwrap().extract::<i32>(py).unwrap());
assert!(seq.get_item(py, 10).is_err());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert_eq!(1, seq.get_item(1).unwrap().extract::<i32>().unwrap());
assert_eq!(2, seq.get_item(2).unwrap().extract::<i32>().unwrap());
assert_eq!(3, seq.get_item(3).unwrap().extract::<i32>().unwrap());
assert_eq!(5, seq.get_item(4).unwrap().extract::<i32>().unwrap());
assert_eq!(8, seq.get_item(5).unwrap().extract::<i32>().unwrap());
assert_eq!(8, seq.get_item(-1).unwrap().extract::<i32>().unwrap());
assert_eq!(5, seq.get_item(-2).unwrap().extract::<i32>().unwrap());
assert_eq!(3, seq.get_item(-3).unwrap().extract::<i32>().unwrap());
assert_eq!(2, seq.get_item(-4).unwrap().extract::<i32>().unwrap());
assert_eq!(1, seq.get_item(-5).unwrap().extract::<i32>().unwrap());
assert!(seq.get_item(10).is_err());
}
// fn test_get_slice() {}
@ -326,22 +328,22 @@ mod test {
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();
assert!(seq.del_item(py, 10).is_err());
assert_eq!(1, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(1, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(2, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(3, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(5, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(8, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(0, seq.len(py).unwrap());
assert!(seq.del_item(py, 0).is_err());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert!(seq.del_item(10).is_err());
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(2, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(3, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(5, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(8, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(0, seq.len().unwrap());
assert!(seq.del_item(0).is_err());
}
#[test]
@ -349,13 +351,13 @@ mod test {
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();
assert_eq!(0, seq.index(py, 1i32).unwrap());
assert_eq!(2, seq.index(py, 2i32).unwrap());
assert_eq!(3, seq.index(py, 3i32).unwrap());
assert_eq!(4, seq.index(py, 5i32).unwrap());
assert_eq!(5, seq.index(py, 8i32).unwrap());
assert!(seq.index(py, 42i32).is_err());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(0, seq.index(1i32).unwrap());
assert_eq!(2, seq.index(2i32).unwrap());
assert_eq!(3, seq.index(3i32).unwrap());
assert_eq!(4, seq.index(5i32).unwrap());
assert_eq!(5, seq.index(8i32).unwrap());
assert!(seq.index(42i32).is_err());
}
#[test]
@ -363,13 +365,13 @@ mod test {
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();
assert_eq!(2, seq.count(py, 1i32).unwrap());
assert_eq!(1, seq.count(py, 2i32).unwrap());
assert_eq!(1, seq.count(py, 3i32).unwrap());
assert_eq!(1, seq.count(py, 5i32).unwrap());
assert_eq!(1, seq.count(py, 8i32).unwrap());
assert_eq!(0, seq.count(py, 42i32).unwrap());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(2, seq.count(1i32).unwrap());
assert_eq!(1, seq.count(2i32).unwrap());
assert_eq!(1, seq.count(3i32).unwrap());
assert_eq!(1, seq.count(5i32).unwrap());
assert_eq!(1, seq.count(8i32).unwrap());
assert_eq!(0, seq.count(42i32).unwrap());
}
#[test]
@ -377,10 +379,10 @@ mod test {
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 seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
let mut idx = 0;
for el in seq.iter(py).unwrap() {
assert_eq!(v[idx], el.unwrap().extract::<i32>(py).unwrap());
for el in seq.iter().unwrap() {
assert_eq!(v[idx], el.unwrap().extract::<i32>().unwrap());
idx += 1;
}
assert_eq!(idx, v.len());
@ -391,13 +393,13 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["It", "was", "the", "worst", "of", "times"];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
let bad_needle = "blurst".to_py_object(py);
assert_eq!(false, seq.contains(py, bad_needle).unwrap());
let bad_needle = "blurst".to_object(py);
assert_eq!(false, seq.contains(bad_needle).unwrap());
let good_needle = "worst".to_py_object(py);
assert_eq!(true, seq.contains(py, good_needle).unwrap());
let good_needle = "worst".to_object(py);
assert_eq!(true, seq.contains(good_needle).unwrap());
}
#[test]
@ -405,12 +407,12 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 2, 3];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(py, &seq).unwrap().cast_into::<PySequence>(py).unwrap();
assert_eq!(6, concat_seq.len(py).unwrap());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(&seq).unwrap();
assert_eq!(6, concat_seq.len().unwrap());
let concat_v : Vec<i32> = vec![1, 2, 3, 1, 2, 3];
for (el, cc) in seq.iter(py).unwrap().zip(concat_v) {
assert_eq!(cc, el.unwrap().extract::<i32>(py).unwrap());
for (el, cc) in seq.iter().unwrap().zip(concat_v) {
assert_eq!(cc, el.unwrap().extract::<i32>().unwrap());
}
}
@ -419,9 +421,9 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "string";
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(py, &seq).unwrap().cast_into::<PySequence>(py).unwrap();
assert_eq!(12, concat_seq.len(py).unwrap());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(&seq).unwrap();
assert_eq!(12, concat_seq.len().unwrap());
/*let concat_v = "stringstring".to_owned();
for (el, cc) in seq.iter(py).unwrap().zip(concat_v.chars()) {
assert_eq!(cc, el.unwrap().extract::<char>(py).unwrap()); //TODO: extract::<char>() is not implemented
@ -433,12 +435,12 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["foo", "bar"];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let repeat_seq = seq.repeat(py, 3).unwrap().cast_into::<PySequence>(py).unwrap();
assert_eq!(6, repeat_seq.len(py).unwrap());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
let repeat_seq = seq.repeat(3).unwrap();
assert_eq!(6, repeat_seq.len().unwrap());
let repeated = vec!["foo", "bar", "foo", "bar", "foo", "bar"];
for (el, rpt) in seq.iter(py).unwrap().zip(repeated.iter()) {
assert_eq!(*rpt, el.unwrap().extract::<String>(py).unwrap());
for (el, rpt) in seq.iter().unwrap().zip(repeated.iter()) {
assert_eq!(*rpt, el.unwrap().extract::<String>().unwrap());
}
}
@ -447,8 +449,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["foo", "bar"];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert!(seq.list(py).is_ok());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert!(seq.list().is_ok());
}
#[test]
@ -456,8 +458,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "foo";
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert!(seq.list(py).is_ok());
let seq = PySequence::downcast_into(py, v.to_object(py)).unwrap();
assert!(seq.list().is_ok());
}
#[test]
@ -465,8 +467,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = ("foo", "bar");
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert!(seq.tuple(py).is_ok());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert!(seq.tuple().is_ok());
}
#[test]
@ -474,15 +476,15 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["foo", "bar"];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert!(seq.tuple(py).is_ok());
let seq = v.to_object(py).into_object(py).cast_into::<PySequence>(py).unwrap();
assert!(seq.tuple().is_ok());
}
#[test]
fn test_extract_tuple_to_vec() {
let gil = Python::acquire_gil();
let py = gil.python();
let v: Vec<i32> = py.eval("(1, 2)", None, None).unwrap().extract(py).unwrap();
let v: Vec<i32> = py.eval("(1, 2)", None, None).unwrap().extract().unwrap();
assert!(v == [1, 2]);
}
@ -490,7 +492,7 @@ mod test {
fn test_extract_range_to_vec() {
let gil = Python::acquire_gil();
let py = gil.python();
let v: Vec<i32> = py.eval("range(1, 5)", None, None).unwrap().extract(py).unwrap();
let v: Vec<i32> = py.eval("range(1, 5)", None, None).unwrap().extract().unwrap();
assert!(v == [1, 2, 3, 4]);
}
@ -498,7 +500,7 @@ mod test {
fn test_extract_bytearray_to_vec() {
let gil = Python::acquire_gil();
let py = gil.python();
let v: Vec<u8> = py.eval("bytearray(b'abc')", None, None).unwrap().extract(py).unwrap();
let v: Vec<u8> = py.eval("bytearray(b'abc')", None, None).unwrap().extract().unwrap();
assert!(v == b"abc");
}
}

View File

@ -4,7 +4,7 @@ use std;
use ffi;
use err::{PyErr, PyResult};
use python::{Python, PyDowncastInto, ToPythonPointer};
use python::{Python, PyDowncastInto, ToPythonPointer, IntoPythonPointer};
use typeob::{PyTypeInfo, PyObjectAlloc};
#[allow(non_camel_case_types)]
@ -167,6 +167,17 @@ impl<'p> ToPythonPointer for pptr<'p> {
}
}
impl<'p> IntoPythonPointer for pptr<'p> {
/// Gets the underlying FFI pointer, returns a owned pointer.
#[inline]
#[must_use]
fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.1;
std::mem::forget(self);
ptr
}
}
/// Dropping a `pptr` instance decrements the reference count on the object by 1.
impl<'p> Drop for pptr<'p> {

View File

@ -43,7 +43,9 @@ pub trait PyDowncastFrom<'p> : Sized {
pub trait PyDowncastInto<'p> : Sized {
/// Cast from PyObject to a concrete Python object type.
fn downcast_into(Python<'p>, PyObject) -> Result<Self, PyDowncastError<'p>>;
fn downcast_into<I>(Python<'p>, I)
-> Result<Self, PyDowncastError<'p>>
where I: ToPythonPointer + IntoPythonPointer;
/// Cast from ffi::PyObject to a concrete Python object type.
fn downcast_from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject)

View File

@ -55,7 +55,7 @@ fn empty_class() {
#[py::class]
struct EmptyClassInModule { }
//#[test]
#[test]
fn empty_class_in_module() {
let gil = Python::acquire_gil();
let py = gil.python();
@ -153,7 +153,7 @@ struct DataIsDropped {
token: PythonToken<DataIsDropped>,
}
//#[test]
#[test]
fn data_is_dropped() {
let gil = Python::acquire_gil();
let py = gil.python();