Merge branch 'master' into pyclass-new-layout
This commit is contained in:
commit
302b3bb088
|
@ -12,6 +12,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
* The blanket implementations for `FromPyObject` for `&T` and `&mut T` are no longer specializable. Implement `PyTryFrom` for your type to control the behavior of `FromPyObject::extract()` for your types.
|
||||
* The implementation for `IntoPy<U> for T` where `U: FromPy<T>` is no longer specializable. Control the behavior of this via the implementation of `FromPy`.
|
||||
|
||||
### Added
|
||||
|
||||
* Implemented `IntoIterator` for `PySet` and `PyFrozenSet`. [#716](https://github.com/PyO3/pyo3/pull/716)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Clear error indicator when the exception is handled on the Rust side. [#719](https://github.com/PyO3/pyo3/pull/719)
|
||||
|
||||
## [0.8.5]
|
||||
|
||||
* Support for `#[name = "foo"]` attribute for `#[pyfunction]` and in `#[pymethods]`. [#692](https://github.com/PyO3/pyo3/pull/692)
|
||||
|
|
|
@ -82,4 +82,13 @@ extern "C" {
|
|||
pub fn PySet_Add(set: *mut PyObject, key: *mut PyObject) -> c_int;
|
||||
#[cfg_attr(PyPy, link_name = "PyPySet_Pop")]
|
||||
pub fn PySet_Pop(set: *mut PyObject) -> *mut PyObject;
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[cfg_attr(PyPy, link_name = "_PySet_NextEntry")]
|
||||
pub fn _PySet_NextEntry(
|
||||
set: *mut PyObject,
|
||||
pos: *mut Py_ssize_t,
|
||||
key: *mut *mut PyObject,
|
||||
hash: *mut super::Py_hash_t,
|
||||
) -> c_int;
|
||||
}
|
||||
|
|
|
@ -155,23 +155,20 @@ impl PyDict {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a iterator of (key, value) pairs in this dictionary
|
||||
/// Note that it's unsafe to use when the dictionary might be changed
|
||||
/// by other python code.
|
||||
/// Returns a iterator of (key, value) pairs in this dictionary.
|
||||
///
|
||||
/// Note that it's unsafe to use when the dictionary might be changed by other code.
|
||||
pub fn iter(&self) -> PyDictIterator {
|
||||
let py = self.py();
|
||||
PyDictIterator {
|
||||
dict: self.to_object(py),
|
||||
dict: self.as_ref(),
|
||||
pos: 0,
|
||||
py,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PyDictIterator<'py> {
|
||||
dict: PyObject,
|
||||
dict: &'py PyAny,
|
||||
pos: isize,
|
||||
py: Python<'py>,
|
||||
}
|
||||
|
||||
impl<'py> Iterator for PyDictIterator<'py> {
|
||||
|
@ -183,7 +180,7 @@ impl<'py> Iterator for PyDictIterator<'py> {
|
|||
let mut key: *mut ffi::PyObject = std::ptr::null_mut();
|
||||
let mut value: *mut ffi::PyObject = std::ptr::null_mut();
|
||||
if ffi::PyDict_Next(self.dict.as_ptr(), &mut self.pos, &mut key, &mut value) != 0 {
|
||||
let py = self.py;
|
||||
let py = self.dict.py();
|
||||
Some((py.from_borrowed_ptr(key), py.from_borrowed_ptr(value)))
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -42,6 +42,7 @@ impl<'p> PyIterator<'p> {
|
|||
let ptr = ffi::PyObject_GetIter(obj.as_ptr());
|
||||
// Returns NULL if an object cannot be iterated.
|
||||
if ptr.is_null() {
|
||||
PyErr::fetch(py);
|
||||
return Err(PyDowncastError);
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ impl PyList {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator over the tuple items.
|
||||
/// Returns an iterator over this list items.
|
||||
pub fn iter(&self) -> PyListIterator {
|
||||
PyListIterator {
|
||||
list: self,
|
||||
|
|
103
src/types/set.rs
103
src/types/set.rs
|
@ -6,6 +6,7 @@ use crate::ffi;
|
|||
use crate::instance::PyNativeType;
|
||||
use crate::internal_tricks::Unsendable;
|
||||
use crate::object::PyObject;
|
||||
use crate::types::PyAny;
|
||||
use crate::AsPyPointer;
|
||||
use crate::Python;
|
||||
use crate::{ToBorrowedObject, ToPyObject};
|
||||
|
@ -97,7 +98,57 @@ impl PySet {
|
|||
|
||||
/// Remove and return an arbitrary element from the set
|
||||
pub fn pop(&self) -> Option<PyObject> {
|
||||
unsafe { PyObject::from_owned_ptr_or_opt(self.py(), ffi::PySet_Pop(self.as_ptr())) }
|
||||
let element =
|
||||
unsafe { PyObject::from_owned_ptr_or_err(self.py(), ffi::PySet_Pop(self.as_ptr())) };
|
||||
match element {
|
||||
Ok(e) => Some(e),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator of values in this set.
|
||||
///
|
||||
/// Note that it can be unsafe to use when the set might be changed by other code.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn iter(&self) -> PySetIterator {
|
||||
PySetIterator {
|
||||
set: self.as_ref(),
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub struct PySetIterator<'py> {
|
||||
set: &'py super::PyAny,
|
||||
pos: isize,
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl<'py> Iterator for PySetIterator<'py> {
|
||||
type Item = &'py super::PyAny;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
let mut key: *mut ffi::PyObject = std::ptr::null_mut();
|
||||
let mut hash: ffi::Py_hash_t = 0;
|
||||
if ffi::_PySet_NextEntry(self.set.as_ptr(), &mut self.pos, &mut key, &mut hash) != 0 {
|
||||
Some(self.set.py().from_borrowed_ptr(key))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl<'a> std::iter::IntoIterator for &'a PySet {
|
||||
type Item = &'a PyAny;
|
||||
type IntoIter = PySetIterator<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,15 +222,34 @@ impl PyFrozenSet {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator of values in this frozen set.
|
||||
///
|
||||
/// Note that it can be unsafe to use when the set might be changed by other code.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn iter(&self) -> PySetIterator {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl<'a> std::iter::IntoIterator for &'a PyFrozenSet {
|
||||
type Item = &'a PyAny;
|
||||
type IntoIter = PySetIterator<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
PySetIterator {
|
||||
set: self.as_ref(),
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{PyFrozenSet, PySet};
|
||||
use crate::instance::AsPyRef;
|
||||
use crate::objectprotocol::ObjectProtocol;
|
||||
use crate::Python;
|
||||
use crate::{PyTryFrom, ToPyObject};
|
||||
use crate::{ObjectProtocol, PyTryFrom, Python, ToPyObject};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[test]
|
||||
|
@ -264,6 +334,9 @@ mod test {
|
|||
assert!(val.is_some());
|
||||
let val2 = set.pop();
|
||||
assert!(val2.is_none());
|
||||
assert!(py
|
||||
.eval("print('Exception state should not be set.')", None, None)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -272,8 +345,15 @@ mod test {
|
|||
let py = gil.python();
|
||||
|
||||
let set = PySet::new(py, &[1]).unwrap();
|
||||
for el in set.iter().unwrap() {
|
||||
assert_eq!(1i32, el.unwrap().extract::<i32>().unwrap());
|
||||
|
||||
// iter method
|
||||
for el in set.iter() {
|
||||
assert_eq!(1i32, el.extract().unwrap());
|
||||
}
|
||||
|
||||
// intoiterator iteration
|
||||
for el in set {
|
||||
assert_eq!(1i32, el.extract().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -311,8 +391,15 @@ mod test {
|
|||
let py = gil.python();
|
||||
|
||||
let set = PyFrozenSet::new(py, &[1]).unwrap();
|
||||
for el in set.iter().unwrap() {
|
||||
assert_eq!(1i32, el.unwrap().extract::<i32>().unwrap());
|
||||
|
||||
// iter method
|
||||
for el in set.iter() {
|
||||
assert_eq!(1i32, el.extract::<i32>().unwrap());
|
||||
}
|
||||
|
||||
// intoiterator iteration
|
||||
for el in set {
|
||||
assert_eq!(1i32, el.extract::<i32>().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,4 +178,7 @@ fn incorrect_iter() {
|
|||
let int_ref = int.as_ref(py);
|
||||
// Should not segfault.
|
||||
assert!(int_ref.iter().is_err());
|
||||
assert!(py
|
||||
.eval("print('Exception state should not be set.')", None, None)
|
||||
.is_ok());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue