mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Add iter, iternext slots & Allow deleting slot magic methods
This commit is contained in:
34 files changed
+866
-936
No files matched your search
@@ -1456,6 +1456,7 @@ class CoroutineTests(unittest.TestCase):
|
||||
self.assertIs(foo(), coro)
|
||||
self.assertIs(foo().__await__(), coro)
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, unittest.mock")
|
||||
def test_duck_gen(self):
|
||||
class GenLike:
|
||||
def send(self): pass
|
||||
|
||||
@@ -92,6 +92,12 @@ pub(crate) fn impl_pyimpl(
|
||||
let mut context = ImplContext::default();
|
||||
extract_items_into_context(&mut context, trai.items.iter_mut());
|
||||
|
||||
let ExtractedImplAttrs {
|
||||
with_impl,
|
||||
with_slots,
|
||||
..
|
||||
} = extract_impl_attrs(attr)?;
|
||||
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
let slots_impl = &context.extend_slots_items;
|
||||
@@ -104,11 +110,13 @@ pub(crate) fn impl_pyimpl(
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
#with_impl
|
||||
#(#class_extensions)*
|
||||
}
|
||||
},
|
||||
parse_quote! {
|
||||
fn __extend_slots(slots: &mut ::rustpython_vm::slots::PyTypeSlots) {
|
||||
#with_slots
|
||||
#slots_impl
|
||||
}
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::function::OptionalArg;
|
||||
use crate::pyobject::{
|
||||
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
@@ -172,22 +173,13 @@ impl PyValue for PyAsyncGenASend {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyAsyncGenASend {
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
#[pymethod(name = "__await__")]
|
||||
fn r#await(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
self.send(vm.ctx.none(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn send(&self, val: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let val = match self.state.load() {
|
||||
@@ -253,6 +245,12 @@ impl PyAsyncGenASend {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PyAsyncGenASend {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
zelf.send(vm.ctx.none(), vm)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "async_generator_athrow")]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PyAsyncGenAThrow {
|
||||
@@ -268,22 +266,13 @@ impl PyValue for PyAsyncGenAThrow {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyAsyncGenAThrow {
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
#[pymethod(name = "__await__")]
|
||||
fn r#await(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
self.send(vm.ctx.none(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn send(&self, val: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
match self.state.load() {
|
||||
@@ -397,6 +386,12 @@ impl PyAsyncGenAThrow {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PyAsyncGenAThrow {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
zelf.send(vm.ctx.none(), vm)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(ctx: &PyContext) {
|
||||
PyAsyncGen::extend_class(ctx, &ctx.types.async_generator);
|
||||
PyAsyncGenASend::extend_class(ctx, &ctx.types.async_generator_asend);
|
||||
|
||||
@@ -21,7 +21,9 @@ use crate::pyobject::{
|
||||
PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex};
|
||||
use crate::slots::{BufferProtocol, Comparable, Hashable, PyComparisonOp, Unhashable};
|
||||
use crate::slots::{
|
||||
BufferProtocol, Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable,
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
use bstr::ByteSlice;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
@@ -97,7 +99,7 @@ pub(crate) fn init(context: &PyContext) {
|
||||
PyByteArrayIterator::extend_class(context, &context.types.bytearray_iterator_type);
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, BufferProtocol))]
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, BufferProtocol, Iterable))]
|
||||
impl PyByteArray {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
@@ -123,14 +125,6 @@ impl PyByteArray {
|
||||
size_of::<Self>() + self.borrow_value().len() * size_of::<u8>()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyByteArrayIterator {
|
||||
PyByteArrayIterator {
|
||||
position: AtomicCell::new(0),
|
||||
bytearray: zelf,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__add__")]
|
||||
fn add(&self, other: PyBytesLike, vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.ctx
|
||||
@@ -718,6 +712,16 @@ impl<'a> ResizeGuard<'a> for PyByteArray {
|
||||
|
||||
impl Unhashable for PyByteArray {}
|
||||
|
||||
impl Iterable for PyByteArray {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyByteArrayIterator {
|
||||
position: AtomicCell::new(0),
|
||||
bytearray: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
// fn set_value(obj: &PyObjectRef, value: Vec<u8>) {
|
||||
// obj.borrow_mut().kind = PyObjectPayload::Bytes { value };
|
||||
// }
|
||||
@@ -735,20 +739,15 @@ impl PyValue for PyByteArrayIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyByteArrayIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult<u8> {
|
||||
let pos = self.position.fetch_add(1);
|
||||
if let Some(&ret) = self.bytearray.borrow_value().elements.get(pos) {
|
||||
Ok(ret)
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyByteArrayIterator {}
|
||||
impl PyIter for PyByteArrayIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = zelf.position.fetch_add(1);
|
||||
if let Some(&ret) = zelf.bytearray.borrow_value().elements.get(pos) {
|
||||
Ok(ret.into_pyobject(vm))
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
+19
-22
@@ -19,7 +19,7 @@ use crate::pyobject::{
|
||||
BorrowValue, Either, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyIterable,
|
||||
PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::slots::{BufferProtocol, Comparable, Hashable, PyComparisonOp};
|
||||
use crate::slots::{BufferProtocol, Comparable, Hashable, Iterable, PyComparisonOp, PyIter};
|
||||
use crate::vm::VirtualMachine;
|
||||
use crate::{
|
||||
anystr::{self, AnyStr},
|
||||
@@ -96,7 +96,7 @@ pub(crate) fn init(context: &PyContext) {
|
||||
PyBytesIterator::extend_class(context, &context.types.bytes_iterator_type);
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, BufferProtocol))]
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, BufferProtocol, Iterable))]
|
||||
impl PyBytes {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
@@ -117,14 +117,6 @@ impl PyBytes {
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyBytesIterator {
|
||||
PyBytesIterator {
|
||||
position: AtomicCell::new(0),
|
||||
bytes: zelf,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__sizeof__")]
|
||||
fn sizeof(&self) -> PyResult<usize> {
|
||||
Ok(size_of::<Self>() + self.inner.elements.len() * size_of::<u8>())
|
||||
@@ -545,6 +537,16 @@ impl Comparable for PyBytes {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyBytes {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyBytesIterator {
|
||||
position: AtomicCell::new(0),
|
||||
bytes: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "bytes_iterator")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyBytesIterator {
|
||||
@@ -558,22 +560,17 @@ impl PyValue for PyBytesIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyBytesIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult<u8> {
|
||||
let pos = self.position.fetch_add(1);
|
||||
if let Some(&ret) = self.bytes.borrow_value().get(pos) {
|
||||
Ok(ret)
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyBytesIterator {}
|
||||
impl PyIter for PyBytesIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = zelf.position.fetch_add(1);
|
||||
if let Some(&ret) = zelf.bytes.borrow_value().get(pos) {
|
||||
Ok(vm.ctx.new_int(ret))
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for PyBytes {
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::coroutine::{Coro, Variant};
|
||||
use crate::frame::FrameRef;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
type PyCoroutineRef = PyRef<PyCoroutine>;
|
||||
@@ -21,7 +22,7 @@ impl PyValue for PyCoroutine {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyCoroutine {
|
||||
pub fn as_coro(&self) -> &Coro {
|
||||
&self.inner
|
||||
@@ -95,6 +96,12 @@ impl PyCoroutine {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PyCoroutine {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
zelf.send(vm.ctx.none(), vm)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "coroutine_wrapper")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyCoroutineWrapper {
|
||||
@@ -109,16 +116,6 @@ impl PyValue for PyCoroutineWrapper {
|
||||
|
||||
#[pyimpl]
|
||||
impl PyCoroutineWrapper {
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
self.coro.send(vm.ctx.none(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn send(&self, val: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
self.coro.send(val, vm)
|
||||
|
||||
+67
-73
@@ -14,7 +14,7 @@ use crate::pyobject::{
|
||||
PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp, Unhashable};
|
||||
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable};
|
||||
use crate::vm::{ReprGuard, VirtualMachine};
|
||||
|
||||
pub type DictContentType = dictdatatype::Dict;
|
||||
@@ -50,7 +50,7 @@ impl PyValue for PyDict {
|
||||
|
||||
// Python dict methods:
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
#[pyimpl(with(Hashable, Comparable), flags(BASETYPE))]
|
||||
#[pyimpl(with(Hashable, Comparable, Iterable), flags(BASETYPE))]
|
||||
impl PyDict {
|
||||
#[pyslot]
|
||||
fn tp_new(class: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
@@ -83,13 +83,13 @@ impl PyDict {
|
||||
dict.insert(vm, key, value)?;
|
||||
}
|
||||
} else if let Some(keys) = vm.get_method(dict_obj.clone(), "keys") {
|
||||
let keys = iterator::get_iter(vm, &vm.invoke(&keys?, ())?)?;
|
||||
let keys = iterator::get_iter(vm, vm.invoke(&keys?, ())?)?;
|
||||
while let Some(key) = iterator::get_next_object(vm, &keys)? {
|
||||
let val = dict_obj.get_item(key.clone(), vm)?;
|
||||
dict.insert(vm, key, val)?;
|
||||
}
|
||||
} else {
|
||||
let iter = iterator::get_iter(vm, &dict_obj)?;
|
||||
let iter = iterator::get_iter(vm, dict_obj)?;
|
||||
loop {
|
||||
fn err(vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
vm.new_value_error("Iterator must have exactly two elements".to_owned())
|
||||
@@ -98,7 +98,7 @@ impl PyDict {
|
||||
Some(obj) => obj,
|
||||
None => break,
|
||||
};
|
||||
let elem_iter = iterator::get_iter(vm, &element)?;
|
||||
let elem_iter = iterator::get_iter(vm, element)?;
|
||||
let key = iterator::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
|
||||
let value =
|
||||
iterator::get_next_object(vm, &elem_iter)?.ok_or_else(|| err(vm))?;
|
||||
@@ -234,11 +234,6 @@ impl PyDict {
|
||||
self.entries.clear()
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>) -> PyDictKeyIterator {
|
||||
PyDictKeyIterator::new(zelf)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn keys(zelf: PyRef<Self>) -> PyDictKeys {
|
||||
PyDictKeys::new(zelf)
|
||||
@@ -420,6 +415,12 @@ impl Comparable for PyDict {
|
||||
|
||||
impl Unhashable for PyDict {}
|
||||
|
||||
impl Iterable for PyDict {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyDictKeyIterator::new(zelf).into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
impl PyDictRef {
|
||||
/// Return an optional inner item, or an error (can be key error as well)
|
||||
#[inline]
|
||||
@@ -579,17 +580,12 @@ macro_rules! dict_iterator {
|
||||
pub dict: PyDictRef,
|
||||
}
|
||||
|
||||
#[pyimpl(with(Comparable))]
|
||||
#[pyimpl(with(Comparable, Iterable))]
|
||||
impl $name {
|
||||
fn new(dict: PyDictRef) -> Self {
|
||||
$name { dict }
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(&self) -> $iter_name {
|
||||
$iter_name::new(self.dict.clone())
|
||||
}
|
||||
|
||||
#[pymethod(name = "__len__")]
|
||||
fn len(&self) -> usize {
|
||||
self.dict.clone().len()
|
||||
@@ -616,6 +612,12 @@ macro_rules! dict_iterator {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for $name {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok($iter_name::new(zelf.dict.clone()).into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
impl Comparable for $name {
|
||||
fn cmp(
|
||||
zelf: &PyRef<Self>,
|
||||
@@ -658,7 +660,13 @@ macro_rules! dict_iterator {
|
||||
pub position: AtomicCell<usize>,
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyValue for $iter_name {
|
||||
fn class(vm: &VirtualMachine) -> &PyTypeRef {
|
||||
&vm.ctx.types.$iter_class
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl $iter_name {
|
||||
fn new(dict: PyDictRef) -> Self {
|
||||
$iter_name {
|
||||
@@ -668,38 +676,28 @@ macro_rules! dict_iterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
if self.dict.entries.has_changed_size(&self.size) {
|
||||
return Err(
|
||||
vm.new_runtime_error("dictionary changed size during iteration".to_owned())
|
||||
);
|
||||
}
|
||||
let mut position = self.position.load();
|
||||
match self.dict.entries.next_entry(&mut position) {
|
||||
Some((key, value)) => {
|
||||
self.position.store(position);
|
||||
Ok($result_fn(vm, key, value))
|
||||
}
|
||||
None => Err(vm.new_stop_iteration()),
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__length_hint__")]
|
||||
fn length_hint(&self) -> usize {
|
||||
self.dict.entries.len_from_entry_index(self.position.load())
|
||||
}
|
||||
}
|
||||
|
||||
impl PyValue for $iter_name {
|
||||
fn class(vm: &VirtualMachine) -> &PyTypeRef {
|
||||
&vm.ctx.types.$iter_class
|
||||
impl PyIter for $iter_name {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
if zelf.dict.entries.has_changed_size(&zelf.size) {
|
||||
return Err(
|
||||
vm.new_runtime_error("dictionary changed size during iteration".to_owned())
|
||||
);
|
||||
}
|
||||
let mut position = zelf.position.load();
|
||||
match zelf.dict.entries.next_entry(&mut position) {
|
||||
Some((key, value)) => {
|
||||
zelf.position.store(position);
|
||||
Ok($result_fn(vm, key, value))
|
||||
}
|
||||
None => Err(vm.new_stop_iteration()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,7 +709,13 @@ macro_rules! dict_iterator {
|
||||
pub position: AtomicCell<usize>,
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyValue for $reverse_iter_name {
|
||||
fn class(vm: &VirtualMachine) -> &PyTypeRef {
|
||||
&vm.ctx.types.$reverse_iter_class
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl $reverse_iter_name {
|
||||
fn new(dict: PyDictRef) -> Self {
|
||||
$reverse_iter_name {
|
||||
@@ -721,41 +725,31 @@ macro_rules! dict_iterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
if self.dict.entries.has_changed_size(&self.size) {
|
||||
return Err(
|
||||
vm.new_runtime_error("dictionary changed size during iteration".to_owned())
|
||||
);
|
||||
}
|
||||
let count = self.position.fetch_add(1);
|
||||
match self.dict.len().checked_sub(count) {
|
||||
Some(mut pos) => {
|
||||
let (key, value) = self.dict.entries.next_entry(&mut pos).unwrap();
|
||||
Ok($result_fn(vm, key, value))
|
||||
}
|
||||
None => {
|
||||
self.position.store(std::isize::MAX as usize);
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__length_hint__")]
|
||||
fn length_hint(&self) -> usize {
|
||||
self.dict.entries.len_from_entry_index(self.position.load())
|
||||
}
|
||||
}
|
||||
|
||||
impl PyValue for $reverse_iter_name {
|
||||
fn class(vm: &VirtualMachine) -> &PyTypeRef {
|
||||
&vm.ctx.types.$reverse_iter_class
|
||||
impl PyIter for $reverse_iter_name {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
if zelf.dict.entries.has_changed_size(&zelf.size) {
|
||||
return Err(
|
||||
vm.new_runtime_error("dictionary changed size during iteration".to_owned())
|
||||
);
|
||||
}
|
||||
let count = zelf.position.fetch_add(1);
|
||||
match zelf.dict.len().checked_sub(count) {
|
||||
Some(mut pos) => {
|
||||
let (key, value) = zelf.dict.entries.next_entry(&mut pos).unwrap();
|
||||
Ok($result_fn(vm, key, value))
|
||||
}
|
||||
None => {
|
||||
zelf.position.store(std::isize::MAX as usize);
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::common::lock::PyRwLock;
|
||||
use std::ops::AddAssign;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::Zero;
|
||||
@@ -8,7 +7,10 @@ use super::int::PyIntRef;
|
||||
use super::pytype::PyTypeRef;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::iterator;
|
||||
use crate::pyobject::{BorrowValue, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::pyobject::{
|
||||
BorrowValue, IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[pyclass(module = false, name = "enumerate")]
|
||||
@@ -24,7 +26,7 @@ impl PyValue for PyEnumerate {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyEnumerate {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
@@ -38,26 +40,22 @@ impl PyEnumerate {
|
||||
OptionalArg::Missing => BigInt::zero(),
|
||||
};
|
||||
|
||||
let iterator = iterator::get_iter(vm, &iterable)?;
|
||||
let iterator = iterator::get_iter(vm, iterable)?;
|
||||
PyEnumerate {
|
||||
counter: PyRwLock::new(counter),
|
||||
iterator,
|
||||
}
|
||||
.into_ref_with_type(vm, cls)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult<(BigInt, PyObjectRef)> {
|
||||
let next_obj = iterator::call_next(vm, &self.iterator)?;
|
||||
let mut counter = self.counter.write();
|
||||
impl PyIter for PyEnumerate {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let next_obj = iterator::call_next(vm, &zelf.iterator)?;
|
||||
let mut counter = zelf.counter.write();
|
||||
let position = counter.clone();
|
||||
AddAssign::add_assign(&mut counter as &mut BigInt, 1);
|
||||
Ok((position, next_obj))
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
*counter += 1;
|
||||
Ok((position, next_obj).into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::pybool;
|
||||
use super::pytype::PyTypeRef;
|
||||
use crate::iterator;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
/// filter(function or None, iterable) --> filter object
|
||||
@@ -21,7 +22,7 @@ impl PyValue for PyFilter {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
#[pyimpl(with(PyIter), flags(BASETYPE))]
|
||||
impl PyFilter {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
@@ -30,7 +31,7 @@ impl PyFilter {
|
||||
iterable: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyRef<Self>> {
|
||||
let iterator = iterator::get_iter(vm, &iterable)?;
|
||||
let iterator = iterator::get_iter(vm, iterable)?;
|
||||
|
||||
Self {
|
||||
predicate: function,
|
||||
@@ -38,11 +39,12 @@ impl PyFilter {
|
||||
}
|
||||
.into_ref_with_type(vm, cls)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let predicate = &self.predicate;
|
||||
let iterator = &self.iterator;
|
||||
impl PyIter for PyFilter {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let predicate = &zelf.predicate;
|
||||
let iterator = &zelf.iterator;
|
||||
loop {
|
||||
let next_obj = iterator::call_next(vm, iterator)?;
|
||||
let predicate_value = if vm.is_none(predicate) {
|
||||
@@ -57,11 +59,6 @@ impl PyFilter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::coroutine::{Coro, Variant};
|
||||
use crate::frame::FrameRef;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[pyclass(module = false, name = "generator")]
|
||||
@@ -22,7 +23,7 @@ impl PyValue for PyGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyGenerator {
|
||||
pub fn as_coro(&self) -> &Coro {
|
||||
&self.inner
|
||||
@@ -41,16 +42,6 @@ impl PyGenerator {
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
self.send(vm.ctx.none(), vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
self.inner.send(value, vm)
|
||||
@@ -95,6 +86,12 @@ impl PyGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PyGenerator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
zelf.send(vm.ctx.none(), vm)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(ctx: &PyContext) {
|
||||
PyGenerator::extend_class(ctx, &ctx.types.generator_type);
|
||||
}
|
||||
+28
-35
@@ -8,6 +8,7 @@ use super::pytype::PyTypeRef;
|
||||
use crate::pyobject::{
|
||||
PyCallable, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[pyclass(module = false, name = "iter")]
|
||||
@@ -24,7 +25,7 @@ impl PyValue for PySequenceIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PySequenceIterator {
|
||||
pub fn new_forward(obj: PyObjectRef) -> Self {
|
||||
Self {
|
||||
@@ -42,28 +43,6 @@ impl PySequenceIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let step: isize = if self.reversed { -1 } else { 1 };
|
||||
let pos = self.position.fetch_add(step);
|
||||
if pos >= 0 {
|
||||
match vm.call_method(&self.obj, "__getitem__", (pos,)) {
|
||||
Err(ref e) if e.isinstance(&vm.ctx.exceptions.index_error) => {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
// also catches stop_iteration => stop_iteration
|
||||
ret => ret,
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__length_hint__")]
|
||||
fn length_hint(&self, vm: &VirtualMachine) -> PyResult<isize> {
|
||||
let pos = self.position.load();
|
||||
@@ -77,6 +56,24 @@ impl PySequenceIterator {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PySequenceIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let step: isize = if zelf.reversed { -1 } else { 1 };
|
||||
let pos = zelf.position.fetch_add(step);
|
||||
if pos >= 0 {
|
||||
match vm.call_method(&zelf.obj, "__getitem__", (pos,)) {
|
||||
Err(ref e) if e.isinstance(&vm.ctx.exceptions.index_error) => {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
// also catches stop_iteration => stop_iteration
|
||||
ret => ret,
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "callable_iterator")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyCallableIterator {
|
||||
@@ -91,7 +88,7 @@ impl PyValue for PyCallableIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyCallableIterator {
|
||||
pub fn new(callable: PyCallable, sentinel: PyObjectRef) -> Self {
|
||||
Self {
|
||||
@@ -100,27 +97,23 @@ impl PyCallableIterator {
|
||||
done: AtomicCell::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
if self.done.load() {
|
||||
impl PyIter for PyCallableIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
if zelf.done.load() {
|
||||
return Err(vm.new_stop_iteration());
|
||||
}
|
||||
|
||||
let ret = self.callable.invoke((), vm)?;
|
||||
let ret = zelf.callable.invoke((), vm)?;
|
||||
|
||||
if vm.bool_eq(&ret, &self.sentinel)? {
|
||||
self.done.store(true);
|
||||
if vm.bool_eq(&ret, &zelf.sentinel)? {
|
||||
zelf.done.store(true);
|
||||
Err(vm.new_stop_iteration())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
|
||||
+36
-42
@@ -15,7 +15,7 @@ use crate::pyobject::{
|
||||
};
|
||||
use crate::sequence::{self, SimpleSeq};
|
||||
use crate::sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex};
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp, Unhashable};
|
||||
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable};
|
||||
use crate::vm::{ReprGuard, VirtualMachine};
|
||||
|
||||
/// Built-in mutable sequence.
|
||||
@@ -79,7 +79,7 @@ pub(crate) struct SortOptions {
|
||||
|
||||
pub type PyListRef = PyRef<PyList>;
|
||||
|
||||
#[pyimpl(with(Hashable, Comparable), flags(BASETYPE))]
|
||||
#[pyimpl(with(Iterable, Hashable, Comparable), flags(BASETYPE))]
|
||||
impl PyList {
|
||||
#[pymethod]
|
||||
pub(crate) fn append(&self, x: PyObjectRef) {
|
||||
@@ -175,14 +175,6 @@ impl PyList {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyListIterator {
|
||||
PyListIterator {
|
||||
position: AtomicCell::new(0),
|
||||
list: zelf,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__setitem__")]
|
||||
fn setitem(
|
||||
&self,
|
||||
@@ -383,6 +375,16 @@ impl PyList {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyList {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyListIterator {
|
||||
position: AtomicCell::new(0),
|
||||
list: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
impl Comparable for PyList {
|
||||
fn cmp(
|
||||
zelf: &PyRef<Self>,
|
||||
@@ -442,24 +444,8 @@ impl PyValue for PyListIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyListIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let list = self.list.borrow_value();
|
||||
let pos = self.position.fetch_add(1);
|
||||
if let Some(obj) = list.get(pos) {
|
||||
Ok(obj.clone())
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__length_hint__")]
|
||||
fn length_hint(&self) -> usize {
|
||||
let list = self.list.borrow_value();
|
||||
@@ -468,6 +454,18 @@ impl PyListIterator {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PyListIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let list = zelf.list.borrow_value();
|
||||
let pos = zelf.position.fetch_add(1);
|
||||
if let Some(obj) = list.get(pos) {
|
||||
Ok(obj.clone())
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "list_reverseiterator")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyListReverseIterator {
|
||||
@@ -481,12 +479,18 @@ impl PyValue for PyListReverseIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyListReverseIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let list = self.list.borrow_value();
|
||||
let pos = self.position.fetch_sub(1);
|
||||
#[pymethod(name = "__length_hint__")]
|
||||
fn length_hint(&self) -> usize {
|
||||
std::cmp::max(self.position.load(), 0) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PyListReverseIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let list = zelf.list.borrow_value();
|
||||
let pos = zelf.position.fetch_sub(1);
|
||||
if pos > 0 {
|
||||
if let Some(ret) = list.get(pos as usize - 1) {
|
||||
return Ok(ret.clone());
|
||||
@@ -494,16 +498,6 @@ impl PyListReverseIterator {
|
||||
}
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__length_hint__")]
|
||||
fn length_hint(&self) -> usize {
|
||||
std::cmp::max(self.position.load(), 0) as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
|
||||
@@ -434,7 +434,7 @@ mod decl {
|
||||
.into_ref(vm)
|
||||
.into_object())
|
||||
} else {
|
||||
iterator::get_iter(vm, &iter_target)
|
||||
iterator::get_iter(vm, iter_target)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,19 +526,16 @@ mod decl {
|
||||
default_value: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
match vm.call_method(&iterator, "__next__", ()) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(value) => {
|
||||
if value.isinstance(&vm.ctx.exceptions.stop_iteration) {
|
||||
match default_value {
|
||||
OptionalArg::Missing => Err(value),
|
||||
OptionalArg::Present(value) => Ok(value),
|
||||
}
|
||||
} else {
|
||||
Err(value)
|
||||
iterator::call_next(vm, &iterator).or_else(|err| {
|
||||
if err.isinstance(&vm.ctx.exceptions.stop_iteration) {
|
||||
match default_value {
|
||||
OptionalArg::Missing => Err(err),
|
||||
OptionalArg::Present(value) => Ok(value),
|
||||
}
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
+16
-19
@@ -2,6 +2,7 @@ use super::pytype::PyTypeRef;
|
||||
use crate::function::Args;
|
||||
use crate::iterator;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
/// map(func, *iterables) --> map object
|
||||
@@ -21,7 +22,7 @@ impl PyValue for PyMap {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
#[pyimpl(with(PyIter), flags(BASETYPE))]
|
||||
impl PyMap {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
@@ -32,7 +33,7 @@ impl PyMap {
|
||||
) -> PyResult<PyRef<Self>> {
|
||||
let iterators = iterables
|
||||
.into_iter()
|
||||
.map(|iterable| iterator::get_iter(vm, &iterable))
|
||||
.map(|iterable| iterator::get_iter(vm, iterable))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
PyMap {
|
||||
mapper: function,
|
||||
@@ -41,23 +42,6 @@ impl PyMap {
|
||||
.into_ref_with_type(vm, cls)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let next_objs = self
|
||||
.iterators
|
||||
.iter()
|
||||
.map(|iterator| iterator::call_next(vm, iterator))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// the mapper itself can raise StopIteration which does stop the map iteration
|
||||
vm.invoke(&self.mapper, next_objs)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__length_hint__")]
|
||||
fn length_hint(&self, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
self.iterators.iter().try_fold(0, |prev, cur| {
|
||||
@@ -68,6 +52,19 @@ impl PyMap {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyIter for PyMap {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let next_objs = zelf
|
||||
.iterators
|
||||
.iter()
|
||||
.map(|iterator| iterator::call_next(vm, iterator))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// the mapper itself can raise StopIteration which does stop the map iteration
|
||||
vm.invoke(&zelf.mapper, next_objs)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
PyMap::extend_class(context, &context.types.map_type);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use crate::pyobject::{
|
||||
BorrowValue, IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult,
|
||||
PyValue, TryFromObject,
|
||||
};
|
||||
use crate::slots::Iterable;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[pyclass(module = false, name = "mappingproxy")]
|
||||
@@ -35,7 +36,7 @@ impl PyMappingProxy {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(Iterable))]
|
||||
impl PyMappingProxy {
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyTypeRef, mapping: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
@@ -85,17 +86,6 @@ impl PyMappingProxy {
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
pub fn iter(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let obj = match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => d.clone(),
|
||||
MappingProxyInner::Class(c) => {
|
||||
// TODO: something that's much more efficient than this
|
||||
PyDict::from_attributes(c.attributes.read().clone(), vm)?.into_pyobject(vm)
|
||||
}
|
||||
};
|
||||
iterator::get_iter(vm, &obj)
|
||||
}
|
||||
#[pymethod]
|
||||
pub fn items(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let obj = match &self.mapping {
|
||||
@@ -136,6 +126,18 @@ impl PyMappingProxy {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Iterable for PyMappingProxy {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let obj = match &zelf.mapping {
|
||||
MappingProxyInner::Dict(d) => d.clone(),
|
||||
MappingProxyInner::Class(c) => {
|
||||
// TODO: something that's much more efficient than this
|
||||
PyDict::from_attributes(c.attributes.read().clone(), vm)?.into_pyobject(vm)
|
||||
}
|
||||
};
|
||||
iterator::get_iter(vm, obj)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
PyMappingProxy::extend_class(context, &context.types.mappingproxy_type)
|
||||
|
||||
+32
-38
@@ -26,7 +26,7 @@ use crate::pyobject::{
|
||||
TypeProtocol,
|
||||
};
|
||||
use crate::sliceable::PySliceableSequence;
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp};
|
||||
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter};
|
||||
use crate::VirtualMachine;
|
||||
use rustpython_common::hash;
|
||||
|
||||
@@ -119,12 +119,13 @@ impl PyValue for PyStrIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyStrIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let value = &*self.string.value;
|
||||
let start = self.position.load();
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyStrIterator {}
|
||||
|
||||
impl PyIter for PyStrIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let value = &*zelf.string.value;
|
||||
let start = zelf.position.load();
|
||||
if start == value.len() {
|
||||
return Err(vm.new_stop_iteration());
|
||||
}
|
||||
@@ -139,18 +140,13 @@ impl PyStrIterator {
|
||||
end.unwrap_or(start + 4)
|
||||
};
|
||||
|
||||
if let Ok(_stored) = self.position.compare_exchange(start, end) {
|
||||
Ok(value[start..end].to_owned())
|
||||
if zelf.position.compare_exchange(start, end).is_ok() {
|
||||
Ok(value[start..end].into_pyobject(vm))
|
||||
} else {
|
||||
// already taken from elsewhere
|
||||
self.next(vm)
|
||||
Self::next(zelf, vm)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "str_reverseiterator")]
|
||||
@@ -166,12 +162,13 @@ impl PyValue for PyStrReverseIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyStrReverseIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let value = &*self.string.value;
|
||||
let end = self.position.load();
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyStrReverseIterator {}
|
||||
|
||||
impl PyIter for PyStrReverseIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let value = &*zelf.string.value;
|
||||
let end = zelf.position.load();
|
||||
if end == 0 {
|
||||
return Err(vm.new_stop_iteration());
|
||||
}
|
||||
@@ -186,18 +183,13 @@ impl PyStrReverseIterator {
|
||||
start.unwrap_or(end - 4)
|
||||
};
|
||||
|
||||
let stored = self.position.swap(start);
|
||||
let stored = zelf.position.swap(start);
|
||||
if end != stored {
|
||||
// already taken from elsewhere
|
||||
return self.next(vm);
|
||||
return Self::next(zelf, vm);
|
||||
}
|
||||
|
||||
Ok(value[start..end].to_owned())
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
Ok(value[start..end].into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +203,7 @@ struct StrArgs {
|
||||
errors: OptionalArg<PyStrRef>,
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable))]
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))]
|
||||
impl PyStr {
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyTypeRef, args: StrArgs, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
@@ -1049,14 +1041,6 @@ impl PyStr {
|
||||
encode_string(zelf, args.encoding, args.errors, vm)
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>) -> PyStrIterator {
|
||||
PyStrIterator {
|
||||
position: AtomicCell::new(0),
|
||||
string: zelf,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn reversed(zelf: PyRef<Self>) -> PyStrReverseIterator {
|
||||
let end = zelf.value.len();
|
||||
@@ -1091,6 +1075,16 @@ impl Comparable for PyStr {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyStr {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyStrIterator {
|
||||
position: AtomicCell::new(0),
|
||||
string: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct EncodeArgs {
|
||||
#[pyarg(any, default)]
|
||||
|
||||
+42
-13
@@ -143,8 +143,13 @@ impl PyType {
|
||||
attributes
|
||||
}
|
||||
|
||||
pub(crate) fn update_slot(&self, name: &str) {
|
||||
pub(crate) fn update_slot(&self, name: &str, add: bool) {
|
||||
// self is the resolved class in get_class_magic
|
||||
macro_rules! update_slot {
|
||||
($name:ident, $func:expr) => {{
|
||||
self.slots.$name.store(if add { Some($func) } else { None });
|
||||
}};
|
||||
}
|
||||
match name {
|
||||
"__call__" => {
|
||||
let func: slots::GenericMethod = |zelf, args, vm| {
|
||||
@@ -152,14 +157,14 @@ impl PyType {
|
||||
let magic = vm.call_if_get_descriptor(magic, zelf.clone())?;
|
||||
vm.invoke(&magic, args)
|
||||
} as _;
|
||||
self.slots.call.store(Some(func))
|
||||
update_slot!(call, func);
|
||||
}
|
||||
"__get__" => {
|
||||
let func: slots::DescrGetFunc = |zelf, obj, cls, vm| {
|
||||
let magic = get_class_magic(&zelf, "__get__");
|
||||
vm.invoke(&magic, (zelf, obj, cls))
|
||||
} as _;
|
||||
self.slots.descr_get.store(Some(func))
|
||||
update_slot!(descr_get, func);
|
||||
}
|
||||
"__hash__" => {
|
||||
let func: slots::HashFunc = |zelf, vm| {
|
||||
@@ -173,7 +178,7 @@ impl PyType {
|
||||
.new_type_error("__hash__ method should return an integer".to_owned())),
|
||||
}
|
||||
} as _;
|
||||
self.slots.hash.store(Some(func));
|
||||
update_slot!(hash, func);
|
||||
}
|
||||
"__del__" => {
|
||||
let func: slots::DelFunc = |zelf, vm| {
|
||||
@@ -181,22 +186,37 @@ impl PyType {
|
||||
let _ = vm.invoke(&magic, vec![zelf.clone()])?;
|
||||
Ok(())
|
||||
} as _;
|
||||
self.slots.del.store(Some(func));
|
||||
update_slot!(del, func);
|
||||
}
|
||||
"__eq__" | "__ne__" | "__le__" | "__lt__" | "__ge__" | "__gt__" => {
|
||||
let func: slots::CmpFunc = |zelf, other, op, vm| {
|
||||
// TODO: differentiate between op types; get_class_magic would panic
|
||||
let magic = get_class_magic(&zelf, op.method_name());
|
||||
vm.invoke(&magic, vec![zelf.clone(), other.clone()])
|
||||
.map(Either::A)
|
||||
} as _;
|
||||
self.slots.cmp.store(Some(func))
|
||||
update_slot!(cmp, func);
|
||||
}
|
||||
"__getattribute__" => {
|
||||
let func: slots::GetattroFunc = |zelf, name, vm| {
|
||||
let magic = get_class_magic(&zelf, "__getattribute__");
|
||||
vm.invoke(&magic, (zelf, name))
|
||||
};
|
||||
self.slots.getattro.store(Some(func))
|
||||
update_slot!(getattro, func);
|
||||
}
|
||||
"__iter__" => {
|
||||
let func: slots::IterFunc = |zelf, vm| {
|
||||
let magic = get_class_magic(&zelf, "__iter__");
|
||||
vm.invoke(&magic, (zelf,))
|
||||
};
|
||||
update_slot!(iter, func);
|
||||
}
|
||||
"__next__" => {
|
||||
let func: slots::IterNextFunc = |zelf, vm| {
|
||||
let magic = get_class_magic(zelf, "__next__");
|
||||
vm.invoke(&magic, (zelf.clone(),))
|
||||
};
|
||||
update_slot!(iternext, func);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -327,10 +347,11 @@ impl PyType {
|
||||
}
|
||||
}
|
||||
let attr_name = attr_name.borrow_value();
|
||||
let mut attributes = zelf.attributes.write();
|
||||
attributes.insert(attr_name.to_owned(), value);
|
||||
if attr_name.starts_with("__") && attr_name.ends_with("__") {
|
||||
zelf.update_slot(attr_name);
|
||||
zelf.update_slot(attr_name, true);
|
||||
}
|
||||
zelf.attributes.write().insert(attr_name.to_owned(), value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -342,9 +363,17 @@ impl PyType {
|
||||
}
|
||||
}
|
||||
|
||||
zelf.get_attr(attr_name.borrow_value())
|
||||
.ok_or_else(|| vm.new_attribute_error(attr_name.borrow_value().to_owned()))?;
|
||||
zelf.attributes.write().remove(attr_name.borrow_value());
|
||||
let mut attributes = zelf.attributes.write();
|
||||
if attributes.remove(attr_name.borrow_value()).is_none() {
|
||||
return Err(vm.new_exception(
|
||||
vm.ctx.exceptions.attribute_error.clone(),
|
||||
vec![attr_name.into_object()],
|
||||
));
|
||||
};
|
||||
let attr_name = attr_name.borrow_value();
|
||||
if attr_name.starts_with("__") && attr_name.ends_with("__") {
|
||||
zelf.update_slot(attr_name, false);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -800,7 +829,7 @@ pub fn new(
|
||||
|
||||
for attr_name in new_type.attributes.read().keys() {
|
||||
if attr_name.starts_with("__") && attr_name.ends_with("__") {
|
||||
new_type.update_slot(attr_name);
|
||||
new_type.update_slot(attr_name, true);
|
||||
}
|
||||
}
|
||||
for base in &new_type.bases {
|
||||
|
||||
+19
-23
@@ -12,7 +12,7 @@ use crate::pyobject::{
|
||||
self, BorrowValue, IdProtocol, IntoPyRef, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult,
|
||||
PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp};
|
||||
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
/// range(stop) -> range object
|
||||
@@ -128,7 +128,7 @@ pub fn init(context: &PyContext) {
|
||||
|
||||
type PyRangeRef = PyRef<PyRange>;
|
||||
|
||||
#[pyimpl(with(Hashable, Comparable))]
|
||||
#[pyimpl(with(Hashable, Comparable, Iterable))]
|
||||
impl PyRange {
|
||||
fn new(cls: PyTypeRef, stop: PyIntRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
PyRange {
|
||||
@@ -168,14 +168,6 @@ impl PyRange {
|
||||
self.step.clone()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRangeIterator {
|
||||
PyRangeIterator {
|
||||
position: AtomicCell::new(0),
|
||||
range: zelf,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__reversed__")]
|
||||
fn reversed(&self, vm: &VirtualMachine) -> PyRangeIterator {
|
||||
let start = self.start.borrow_value();
|
||||
@@ -368,6 +360,16 @@ impl Comparable for PyRange {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyRange {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyRangeIterator {
|
||||
position: AtomicCell::new(0),
|
||||
range: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "range_iterator")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyRangeIterator {
|
||||
@@ -381,24 +383,18 @@ impl PyValue for PyRangeIterator {
|
||||
}
|
||||
}
|
||||
|
||||
type PyRangeIteratorRef = PyRef<PyRangeIterator>;
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyRangeIterator {}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyRangeIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult<BigInt> {
|
||||
let position = BigInt::from(self.position.fetch_add(1));
|
||||
if let Some(int) = self.range.get(&position) {
|
||||
Ok(int)
|
||||
impl PyIter for PyRangeIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let position = BigInt::from(zelf.position.fetch_add(1));
|
||||
if let Some(int) = zelf.range.get(&position) {
|
||||
Ok(vm.ctx.new_int(int))
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRangeIteratorRef {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RangeIndex {
|
||||
|
||||
+45
-46
@@ -10,8 +10,9 @@ use crate::pyobject::{
|
||||
self, BorrowValue, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef,
|
||||
PyResult, PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp, Unhashable};
|
||||
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter, Unhashable};
|
||||
use crate::vm::{ReprGuard, VirtualMachine};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use std::fmt;
|
||||
|
||||
pub type SetContentType = dictdatatype::Dict<()>;
|
||||
@@ -192,7 +193,7 @@ impl PySetInner {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn iter(&self, _vm: &VirtualMachine) -> PySetIterator {
|
||||
fn iter(&self) -> PySetIterator {
|
||||
let set_size = SetSizeInfo {
|
||||
position: 0,
|
||||
size: Some(self.content.len()),
|
||||
@@ -200,7 +201,7 @@ impl PySetInner {
|
||||
|
||||
PySetIterator {
|
||||
dict: PyRc::clone(&self.content),
|
||||
size_info: crossbeam_utils::atomic::AtomicCell::new(set_size),
|
||||
size_info: AtomicCell::new(set_size),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +312,7 @@ macro_rules! multi_args_set {
|
||||
}};
|
||||
}
|
||||
|
||||
#[pyimpl(with(Hashable, Comparable), flags(BASETYPE))]
|
||||
#[pyimpl(with(Hashable, Comparable, Iterable), flags(BASETYPE))]
|
||||
impl PySet {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
@@ -426,11 +427,6 @@ impl PySet {
|
||||
self.xor(other, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(&self, vm: &VirtualMachine) -> PySetIterator {
|
||||
self.inner.iter(vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__repr__")]
|
||||
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let s = if zelf.inner.len() == 0 {
|
||||
@@ -539,6 +535,12 @@ impl Comparable for PySet {
|
||||
|
||||
impl Unhashable for PySet {}
|
||||
|
||||
impl Iterable for PySet {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(zelf.inner.iter().into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! multi_args_frozenset {
|
||||
($vm:expr, $others:expr, $zelf:expr, $op:tt) => {{
|
||||
let mut res = $zelf.inner.copy();
|
||||
@@ -549,7 +551,7 @@ macro_rules! multi_args_frozenset {
|
||||
}};
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable))]
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))]
|
||||
impl PyFrozenSet {
|
||||
// used by ssl.rs windows
|
||||
#[allow(dead_code)]
|
||||
@@ -677,11 +679,6 @@ impl PyFrozenSet {
|
||||
self.xor(other, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(&self, vm: &VirtualMachine) -> PySetIterator {
|
||||
self.inner.iter(vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__repr__")]
|
||||
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let inner = &zelf.inner;
|
||||
@@ -715,6 +712,12 @@ impl Comparable for PyFrozenSet {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyFrozenSet {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(zelf.inner.iter().into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
struct SetIterable {
|
||||
iterable: Args<PyIterable>,
|
||||
}
|
||||
@@ -745,7 +748,7 @@ struct SetSizeInfo {
|
||||
#[pyclass(module = false, name = "set_iterator")]
|
||||
pub(crate) struct PySetIterator {
|
||||
dict: PyRc<SetContentType>,
|
||||
size_info: crossbeam_utils::atomic::AtomicCell<SetSizeInfo>,
|
||||
size_info: AtomicCell<SetSizeInfo>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PySetIterator {
|
||||
@@ -755,34 +758,14 @@ impl fmt::Debug for PySetIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyValue for PySetIterator {
|
||||
fn class(vm: &VirtualMachine) -> &PyTypeRef {
|
||||
&vm.ctx.types.set_iterator_type
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PySetIterator {
|
||||
#[pymethod(magic)]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let mut size_info = self.size_info.take();
|
||||
|
||||
if let Some(set_size) = size_info.size {
|
||||
if set_size == self.dict.len() {
|
||||
let index = size_info.position;
|
||||
let keys = self.dict.keys();
|
||||
let item = keys.get(index).ok_or_else(|| vm.new_stop_iteration())?;
|
||||
size_info.position += 1;
|
||||
self.size_info.store(size_info);
|
||||
return Ok(item.clone());
|
||||
} else {
|
||||
size_info.size = None;
|
||||
self.size_info.store(size_info);
|
||||
}
|
||||
}
|
||||
|
||||
Err(vm.new_runtime_error("set changed size during iteration".into()))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
let set_len = self.dict.len();
|
||||
@@ -791,9 +774,25 @@ impl PySetIterator {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyValue for PySetIterator {
|
||||
fn class(vm: &VirtualMachine) -> &PyTypeRef {
|
||||
&vm.ctx.types.set_iterator_type
|
||||
impl PyIter for PySetIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let mut size_info = zelf.size_info.take();
|
||||
|
||||
if let Some(set_size) = size_info.size {
|
||||
if set_size == zelf.dict.len() {
|
||||
let index = size_info.position;
|
||||
let keys = zelf.dict.keys();
|
||||
let item = keys.get(index).ok_or_else(|| vm.new_stop_iteration())?;
|
||||
size_info.position += 1;
|
||||
zelf.size_info.store(size_info);
|
||||
return Ok(item.clone());
|
||||
} else {
|
||||
size_info.size = None;
|
||||
zelf.size_info.store(size_info);
|
||||
}
|
||||
}
|
||||
|
||||
Err(vm.new_runtime_error("set changed size during iteration".into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-21
@@ -10,7 +10,7 @@ use crate::pyobject::{
|
||||
};
|
||||
use crate::sequence::{self, SimpleSeq};
|
||||
use crate::sliceable::PySliceableSequence;
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp};
|
||||
use crate::slots::{Comparable, Hashable, Iterable, PyComparisonOp, PyIter};
|
||||
use crate::vm::{ReprGuard, VirtualMachine};
|
||||
|
||||
/// tuple() -> empty tuple
|
||||
@@ -84,7 +84,7 @@ pub(crate) fn get_value(obj: &PyObjectRef) -> &[PyObjectRef] {
|
||||
obj.payload::<PyTuple>().unwrap().borrow_value()
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable))]
|
||||
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable))]
|
||||
impl PyTuple {
|
||||
/// Creating a new tuple with given boxed slice.
|
||||
/// NOTE: for usual case, you probably want to use PyTupleRef::with_elements.
|
||||
@@ -134,14 +134,6 @@ impl PyTuple {
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyTupleIterator {
|
||||
PyTupleIterator {
|
||||
position: AtomicCell::new(0),
|
||||
tuple: zelf,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__len__")]
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.elements.len()
|
||||
@@ -258,6 +250,16 @@ impl Comparable for PyTuple {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyTuple {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyTupleIterator {
|
||||
position: AtomicCell::new(0),
|
||||
tuple: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "tuple_iterator")]
|
||||
#[derive(Debug)]
|
||||
pub struct PyTupleIterator {
|
||||
@@ -271,22 +273,18 @@ impl PyValue for PyTupleIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyTupleIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = self.position.fetch_add(1);
|
||||
if let Some(obj) = self.tuple.borrow_value().get(pos) {
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyTupleIterator {}
|
||||
|
||||
impl PyIter for PyTupleIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = zelf.position.fetch_add(1);
|
||||
if let Some(obj) = zelf.tuple.borrow_value().get(pos) {
|
||||
Ok(obj.clone())
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
|
||||
+8
-11
@@ -2,6 +2,7 @@ use super::pytype::PyTypeRef;
|
||||
use crate::function::Args;
|
||||
use crate::iterator;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
pub type PyZipRef = PyRef<PyZip>;
|
||||
@@ -18,23 +19,24 @@ impl PyValue for PyZip {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
#[pyimpl(with(PyIter), flags(BASETYPE))]
|
||||
impl PyZip {
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyTypeRef, iterables: Args, vm: &VirtualMachine) -> PyResult<PyZipRef> {
|
||||
let iterators = iterables
|
||||
.into_iter()
|
||||
.map(|iterable| iterator::get_iter(vm, &iterable))
|
||||
.map(|iterable| iterator::get_iter(vm, iterable))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
PyZip { iterators }.into_ref_with_type(vm, cls)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
if self.iterators.is_empty() {
|
||||
impl PyIter for PyZip {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
if zelf.iterators.is_empty() {
|
||||
Err(vm.new_stop_iteration())
|
||||
} else {
|
||||
let next_objs = self
|
||||
let next_objs = zelf
|
||||
.iterators
|
||||
.iter()
|
||||
.map(|iterator| iterator::call_next(vm, iterator))
|
||||
@@ -43,11 +45,6 @@ impl PyZip {
|
||||
Ok(vm.ctx.new_tuple(next_objs))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
|
||||
+1
-1
@@ -583,7 +583,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::GetIter => {
|
||||
let iterated_obj = self.pop_value();
|
||||
let iter_obj = iterator::get_iter(vm, &iterated_obj)?;
|
||||
let iter_obj = iterator::get_iter(vm, iterated_obj)?;
|
||||
self.push_value(iter_obj);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
+19
-8
@@ -14,30 +14,41 @@ use num_traits::Signed;
|
||||
* in the vm when a for loop is entered. Next, it is used when the builtin
|
||||
* function 'iter' is called.
|
||||
*/
|
||||
pub fn get_iter(vm: &VirtualMachine, iter_target: &PyObjectRef) -> PyResult {
|
||||
if let Some(method_or_err) = vm.get_method(iter_target.clone(), "__iter__") {
|
||||
let method = method_or_err?;
|
||||
let iter = vm.invoke(&method, ())?;
|
||||
if iter.has_class_attr("__next__") {
|
||||
pub fn get_iter(vm: &VirtualMachine, iter_target: PyObjectRef) -> PyResult {
|
||||
let getiter = {
|
||||
let cls = iter_target.class();
|
||||
cls.mro_find_map(|x| x.slots.iter.load())
|
||||
};
|
||||
if let Some(getiter) = getiter {
|
||||
let iter = getiter(iter_target, vm)?;
|
||||
let cls = iter.class();
|
||||
let is_iter = cls.iter_mro().any(|x| x.slots.iternext.load().is_some());
|
||||
if is_iter {
|
||||
drop(cls);
|
||||
Ok(iter)
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"iter() returned non-iterator of type '{}'",
|
||||
iter.class().name
|
||||
cls.name
|
||||
)))
|
||||
}
|
||||
} else {
|
||||
vm.get_method_or_type_error(iter_target.clone(), "__getitem__", || {
|
||||
format!("'{}' object is not iterable", iter_target.class().name)
|
||||
})?;
|
||||
Ok(PySequenceIterator::new_forward(iter_target.clone())
|
||||
Ok(PySequenceIterator::new_forward(iter_target)
|
||||
.into_ref(vm)
|
||||
.into_object())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_next(vm: &VirtualMachine, iter_obj: &PyObjectRef) -> PyResult {
|
||||
vm.call_method(iter_obj, "__next__", ())
|
||||
let iternext = {
|
||||
let cls = iter_obj.class();
|
||||
cls.mro_find_map(|x| x.slots.iternext.load())
|
||||
.ok_or_else(|| vm.new_type_error(format!("'{}' object is not an iterator", cls.name)))?
|
||||
};
|
||||
iternext(iter_obj, vm)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+24
-39
@@ -840,25 +840,21 @@ impl fmt::Debug for PyObject<dyn PyObjectPayload> {
|
||||
/// PyIterable can optionally perform type checking and conversions on iterated
|
||||
/// objects using a generic type parameter that implements `TryFromObject`.
|
||||
pub struct PyIterable<T = PyObjectRef> {
|
||||
method: PyObjectRef,
|
||||
_item: std::marker::PhantomData<T>,
|
||||
iterable: PyObjectRef,
|
||||
iterfn: Option<crate::slots::IterFunc>,
|
||||
_item: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> PyIterable<T> {
|
||||
pub fn from_method(method: PyObjectRef) -> Self {
|
||||
PyIterable {
|
||||
method,
|
||||
_item: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over this sequence of objects.
|
||||
///
|
||||
/// This operation may fail if an exception is raised while invoking the
|
||||
/// `__iter__` method of the iterable object.
|
||||
pub fn iter<'a>(&self, vm: &'a VirtualMachine) -> PyResult<PyIterator<'a, T>> {
|
||||
let method = &self.method;
|
||||
let iter_obj = vm.invoke(method, ())?;
|
||||
let iter_obj = match self.iterfn {
|
||||
Some(f) => f(self.iterable.clone(), vm)?,
|
||||
None => PySequenceIterator::new_forward(self.iterable.clone()).into_object(vm),
|
||||
};
|
||||
|
||||
let length_hint = iterator::length_hint(vm, iter_obj.clone())?;
|
||||
|
||||
@@ -866,7 +862,7 @@ impl<T> PyIterable<T> {
|
||||
vm,
|
||||
obj: iter_obj,
|
||||
length_hint,
|
||||
_item: std::marker::PhantomData,
|
||||
_item: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -876,23 +872,19 @@ where
|
||||
T: TryFromObject,
|
||||
{
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
if let Some(method_or_err) = vm.get_method(obj.clone(), "__iter__") {
|
||||
let method = method_or_err?;
|
||||
Ok(PyIterable {
|
||||
method,
|
||||
_item: std::marker::PhantomData,
|
||||
})
|
||||
} else {
|
||||
vm.get_method_or_type_error(obj.clone(), "__getitem__", || {
|
||||
format!("'{}' object is not iterable", obj.class().name)
|
||||
})?;
|
||||
Self::try_from_object(
|
||||
vm,
|
||||
PySequenceIterator::new_forward(obj)
|
||||
.into_ref(vm)
|
||||
.into_object(),
|
||||
)
|
||||
let iterfn;
|
||||
{
|
||||
let cls = obj.class();
|
||||
iterfn = cls.mro_find_map(|x| x.slots.iter.load());
|
||||
if iterfn.is_none() && !cls.has_attr("__getitem__") {
|
||||
return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name)));
|
||||
}
|
||||
}
|
||||
Ok(PyIterable {
|
||||
iterable: obj,
|
||||
iterfn,
|
||||
_item: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -900,7 +892,7 @@ pub struct PyIterator<'a, T> {
|
||||
vm: &'a VirtualMachine,
|
||||
obj: PyObjectRef,
|
||||
length_hint: Option<usize>,
|
||||
_item: std::marker::PhantomData<T>,
|
||||
_item: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for PyIterator<'a, T>
|
||||
@@ -910,16 +902,9 @@ where
|
||||
type Item = PyResult<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.vm.call_method(&self.obj, "__next__", ()) {
|
||||
Ok(value) => Some(T::try_from_object(self.vm, value)),
|
||||
Err(err) => {
|
||||
if err.isinstance(&self.vm.ctx.exceptions.stop_iteration) {
|
||||
None
|
||||
} else {
|
||||
Some(Err(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator::get_next_object(self.vm, &self.obj)
|
||||
.transpose()
|
||||
.map(|x| x.and_then(|obj| T::try_from_object(self.vm, obj)))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
|
||||
@@ -55,6 +55,8 @@ pub(crate) type CmpFunc = fn(
|
||||
) -> PyResult<Either<PyObjectRef, PyComparisonValue>>;
|
||||
pub(crate) type GetattroFunc = fn(PyObjectRef, PyStrRef, &VirtualMachine) -> PyResult;
|
||||
pub(crate) type BufferFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult<Box<dyn Buffer>>;
|
||||
pub(crate) type IterFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult;
|
||||
pub(crate) type IterNextFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyTypeSlots {
|
||||
@@ -68,6 +70,8 @@ pub struct PyTypeSlots {
|
||||
pub cmp: AtomicCell<Option<CmpFunc>>,
|
||||
pub getattro: AtomicCell<Option<GetattroFunc>>,
|
||||
pub buffer: Option<BufferFunc>,
|
||||
pub iter: AtomicCell<Option<IterFunc>>,
|
||||
pub iternext: AtomicCell<Option<IterNextFunc>>,
|
||||
}
|
||||
|
||||
impl PyTypeSlots {
|
||||
@@ -418,3 +422,49 @@ pub trait BufferProtocol: PyValue {
|
||||
|
||||
fn get_buffer(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>>;
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
pub trait Iterable: PyValue {
|
||||
#[pyslot]
|
||||
fn tp_iter(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if let Ok(zelf) = zelf.downcast() {
|
||||
Self::iter(zelf, vm)
|
||||
} else {
|
||||
Err(vm.new_type_error("unexpected payload for __iter__".to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult;
|
||||
}
|
||||
|
||||
#[pyimpl(with(Iterable))]
|
||||
pub trait PyIter: PyValue {
|
||||
#[pyslot]
|
||||
fn tp_iternext(zelf: &PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(zelf) = zelf.downcast_ref() {
|
||||
Self::next(zelf, vm)
|
||||
} else {
|
||||
Err(vm.new_type_error("unexpected payload for __next__".to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult;
|
||||
|
||||
#[pymethod]
|
||||
fn __next__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Self::next(&zelf, vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterable for T
|
||||
where
|
||||
T: PyIter,
|
||||
{
|
||||
fn tp_iter(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult {
|
||||
Ok(zelf)
|
||||
}
|
||||
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult {
|
||||
Ok(zelf.into_object())
|
||||
}
|
||||
}
|
||||
+19
-21
@@ -16,7 +16,7 @@ use crate::pyobject::{
|
||||
PyObjectRef, PyRef, PyResult, PyValue, StaticType, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::sliceable::{saturate_index, PySliceableSequence, PySliceableSequenceMut};
|
||||
use crate::slots::{BufferProtocol, Comparable, PyComparisonOp};
|
||||
use crate::slots::{BufferProtocol, Comparable, Iterable, PyComparisonOp, PyIter};
|
||||
use crate::VirtualMachine;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use itertools::Itertools;
|
||||
@@ -486,7 +486,7 @@ impl From<ArrayContentType> for PyArray {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Comparable, BufferProtocol))]
|
||||
#[pyimpl(flags(BASETYPE), with(Comparable, BufferProtocol, Iterable))]
|
||||
impl PyArray {
|
||||
fn borrow_value(&self) -> PyRwLockReadGuard<'_, ArrayContentType> {
|
||||
self.array.read()
|
||||
@@ -766,14 +766,6 @@ impl PyArray {
|
||||
self.borrow_value().len()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyArrayIter {
|
||||
PyArrayIter {
|
||||
position: AtomicCell::new(0),
|
||||
array: zelf,
|
||||
}
|
||||
}
|
||||
|
||||
fn array_eq(&self, other: &Self, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
// we cannot use zelf.is(other) for shortcut because if we contenting a
|
||||
// float value NaN we always return False even they are the same object.
|
||||
@@ -889,6 +881,16 @@ impl Buffer for ArrayBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyArray {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyArrayIter {
|
||||
position: AtomicCell::new(0),
|
||||
array: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ResizeGuard<'a> for PyArray {
|
||||
type Resizable = PyRwLockWriteGuard<'a, ArrayContentType>;
|
||||
|
||||
@@ -916,22 +918,18 @@ impl PyValue for PyArrayIter {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyArrayIter {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = self.position.fetch_add(1);
|
||||
if let Some(item) = self.array.borrow_value().getitem_by_idx(pos, vm) {
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyArrayIter {}
|
||||
|
||||
impl PyIter for PyArrayIter {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = zelf.position.fetch_add(1);
|
||||
if let Some(item) = zelf.array.borrow_value().getitem_by_idx(pos, vm) {
|
||||
Ok(item)
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
|
||||
@@ -8,7 +8,7 @@ mod _collections {
|
||||
use crate::pyobject::{
|
||||
PyComparisonValue, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, StaticType,
|
||||
};
|
||||
use crate::slots::{Comparable, PyComparisonOp};
|
||||
use crate::slots::{Comparable, Iterable, PyComparisonOp, PyIter};
|
||||
use crate::vm::ReprGuard;
|
||||
use crate::VirtualMachine;
|
||||
use crate::{sequence, sliceable};
|
||||
@@ -66,7 +66,7 @@ mod _collections {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Comparable))]
|
||||
#[pyimpl(flags(BASETYPE), with(Comparable, Iterable))]
|
||||
impl PyDeque {
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
@@ -323,14 +323,6 @@ mod _collections {
|
||||
fn len(&self) -> usize {
|
||||
self.borrow_deque().len()
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>) -> PyDequeIterator {
|
||||
PyDequeIterator {
|
||||
position: AtomicCell::new(0),
|
||||
deque: zelf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Comparable for PyDeque {
|
||||
@@ -350,6 +342,16 @@ mod _collections {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyDeque {
|
||||
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(PyDequeIterator {
|
||||
position: AtomicCell::new(0),
|
||||
deque: zelf,
|
||||
}
|
||||
.into_object(vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(name = "_deque_iterator")]
|
||||
#[derive(Debug)]
|
||||
@@ -364,12 +366,13 @@ mod _collections {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyDequeIterator {
|
||||
#[pymethod(magic)]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = self.position.fetch_add(1);
|
||||
let deque = self.deque.borrow_deque();
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl PyDequeIterator {}
|
||||
|
||||
impl PyIter for PyDequeIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let pos = zelf.position.fetch_add(1);
|
||||
let deque = zelf.deque.borrow_deque();
|
||||
if pos < deque.len() {
|
||||
let ret = deque[pos].clone();
|
||||
Ok(ret)
|
||||
@@ -377,10 +380,5 @@ mod _collections {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-7
@@ -7,8 +7,8 @@ use crate::builtins::pytype::PyTypeRef;
|
||||
use crate::common::lock::PyRwLock;
|
||||
use crate::function::FuncArgs;
|
||||
use crate::pyobject::{
|
||||
BorrowValue, IntoPyObject, PyClassImpl, PyIterable, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
StaticType, TryFromObject, TypeProtocol,
|
||||
BorrowValue, IntoPyObject, PyClassImpl, PyIterable, PyObjectRef, PyResult, PyValue, StaticType,
|
||||
TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::types::create_simple_type;
|
||||
use crate::VirtualMachine;
|
||||
@@ -149,15 +149,24 @@ impl Reader {
|
||||
|
||||
#[pyimpl]
|
||||
impl Reader {
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(this: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
#[pyslot]
|
||||
#[pymethod(magic)]
|
||||
fn iter(this: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let this = match this.downcast::<Self>() {
|
||||
Ok(reader) => reader,
|
||||
Err(_) => return Err(vm.new_type_error("unexpected payload for __iter__".to_owned())),
|
||||
};
|
||||
this.state.write().cast_to_reader(vm)?;
|
||||
Ok(this.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let mut state = self.state.write();
|
||||
#[pyslot]
|
||||
fn tp_iternext(zelf: &PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let zelf = match zelf.downcast_ref::<Self>() {
|
||||
Some(reader) => reader,
|
||||
None => return Err(vm.new_type_error("unexpected payload for __next__".to_owned())),
|
||||
};
|
||||
let mut state = zelf.state.write();
|
||||
state.cast_to_reader(vm)?;
|
||||
|
||||
if let ReadState::CsvIter(ref mut reader) = &mut *state {
|
||||
|
||||
@@ -14,7 +14,7 @@ mod _functools {
|
||||
start_value: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let iterator = iterator::get_iter(vm, &sequence)?;
|
||||
let iterator = iterator::get_iter(vm, sequence)?;
|
||||
|
||||
let start_value = if let OptionalArg::Present(val) = start_value {
|
||||
val
|
||||
|
||||
+9
-4
@@ -453,13 +453,14 @@ mod _io {
|
||||
check_seekable(&instance, vm)
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
#[pyslot]
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn tp_iter(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
check_closed(&instance, vm)?;
|
||||
Ok(instance)
|
||||
}
|
||||
#[pymethod(magic)]
|
||||
fn next(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
#[pyslot]
|
||||
fn tp_iternext(instance: &PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let line = call_method(vm, &instance, "readline", ())?;
|
||||
if !pybool::boolval(vm, line.clone())? {
|
||||
Err(vm.new_stop_iteration())
|
||||
@@ -467,6 +468,10 @@ mod _io {
|
||||
Ok(line)
|
||||
}
|
||||
}
|
||||
#[pymethod(magic)]
|
||||
fn next(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
Self::tp_iternext(&instance, vm)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn iobase_close(file: &PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
|
||||
+229
-327
File diff suppressed because it is too large.
Load diff
+25
-29
@@ -25,6 +25,7 @@ use crate::pyobject::{
|
||||
BorrowValue, Either, IntoPyObject, ItemProtocol, PyObjectRef, PyRef, PyResult,
|
||||
PyStructSequence, PyValue, StaticType, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::slots::PyIter;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
// this is basically what CPython has for Py_off_t; windows uses long long
|
||||
@@ -656,41 +657,13 @@ mod _os {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl ScandirIterator {
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
if self.exhausted.load() {
|
||||
return Err(vm.new_stop_iteration());
|
||||
}
|
||||
|
||||
match self.entries.write().next() {
|
||||
Some(entry) => match entry {
|
||||
Ok(entry) => Ok(DirEntry {
|
||||
entry,
|
||||
mode: self.mode,
|
||||
}
|
||||
.into_ref(vm)
|
||||
.into_object()),
|
||||
Err(err) => Err(err.into_pyexception(vm)),
|
||||
},
|
||||
None => {
|
||||
self.exhausted.store(true);
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn close(&self) {
|
||||
self.exhausted.store(true);
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(name = "__enter__")]
|
||||
fn enter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
@@ -701,6 +674,29 @@ mod _os {
|
||||
zelf.close()
|
||||
}
|
||||
}
|
||||
impl PyIter for ScandirIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
if zelf.exhausted.load() {
|
||||
return Err(vm.new_stop_iteration());
|
||||
}
|
||||
|
||||
match zelf.entries.write().next() {
|
||||
Some(entry) => match entry {
|
||||
Ok(entry) => Ok(DirEntry {
|
||||
entry,
|
||||
mode: zelf.mode,
|
||||
}
|
||||
.into_ref(vm)
|
||||
.into_object()),
|
||||
Err(err) => Err(err.into_pyexception(vm)),
|
||||
},
|
||||
None => {
|
||||
zelf.exhausted.store(true);
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn scandir(path: OptionalArg<PyPathLike>, vm: &VirtualMachine) -> PyResult {
|
||||
|
||||
+15
-18
@@ -35,6 +35,7 @@ pub(crate) mod _struct {
|
||||
BorrowValue, Either, IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue, StaticType,
|
||||
TryFromObject,
|
||||
};
|
||||
use crate::slots::PyIter;
|
||||
use crate::VirtualMachine;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@@ -832,30 +833,26 @@ pub(crate) mod _struct {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
#[pyimpl(with(PyIter))]
|
||||
impl UnpackIterator {
|
||||
#[pymethod(magic)]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
let size = self.format_spec.size();
|
||||
let offset = self.offset.fetch_add(size);
|
||||
if offset + size > self.buffer.len() {
|
||||
Err(vm.new_stop_iteration())
|
||||
} else {
|
||||
self.buffer
|
||||
.with_ref(|buf| self.format_spec.unpack(&buf[offset..offset + size], vm))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn iter(zelf: PyRef<Self>) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
self.buffer.len().saturating_sub(self.offset.load()) / self.format_spec.size()
|
||||
}
|
||||
}
|
||||
impl PyIter for UnpackIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
let size = zelf.format_spec.size();
|
||||
let offset = zelf.offset.fetch_add(size);
|
||||
zelf.buffer.with_ref(|buf| {
|
||||
if let Some(buf) = buf.get(offset..offset + size) {
|
||||
zelf.format_spec.unpack(buf, vm).map(|x| x.into_object())
|
||||
} else {
|
||||
Err(vm.new_stop_iteration())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn iter_unpack(
|
||||
|
||||
+3
-3
@@ -1011,7 +1011,7 @@ impl VirtualMachine {
|
||||
.map(|obj| T::try_from_object(self, obj.clone()))
|
||||
.collect()
|
||||
} else {
|
||||
let iter = iterator::get_iter(self, value)?;
|
||||
let iter = iterator::get_iter(self, value.clone())?;
|
||||
iterator::get_all(self, &iter)
|
||||
}
|
||||
}
|
||||
@@ -1049,7 +1049,7 @@ impl VirtualMachine {
|
||||
ref t @ PyTuple => Ok(t.borrow_value().iter().cloned().map(f).collect()),
|
||||
// TODO: put internal iterable type
|
||||
obj => {
|
||||
let iter = iterator::get_iter(self, obj)?;
|
||||
let iter = iterator::get_iter(self, obj.clone())?;
|
||||
Ok(iterator::try_map(self, &iter, f))
|
||||
}
|
||||
})
|
||||
@@ -1574,7 +1574,7 @@ impl VirtualMachine {
|
||||
|
||||
// https://docs.python.org/3/reference/expressions.html#membership-test-operations
|
||||
fn _membership_iter_search(&self, haystack: PyObjectRef, needle: PyObjectRef) -> PyResult {
|
||||
let iter = iterator::get_iter(self, &haystack)?;
|
||||
let iter = iterator::get_iter(self, haystack)?;
|
||||
loop {
|
||||
if let Some(element) = iterator::get_next_object(self, &iter)? {
|
||||
if self.bool_eq(&needle, &element)? {
|
||||
|
||||
Reference in new issue
Block a user