Skip to content

Commit 4632972

Browse files
authored
Implement missing Iterator & ReverseIterator and its methods (RustPython#2906)
Implement missing methods of string iterators.
1 parent 0a6edab commit 4632972

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

Lib/test/test_iter.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,6 @@ def test_iter_range(self):
313313
self.check_for_loop(iter(range(10)), list(range(10)))
314314

315315
# Test a string
316-
# TODO: RUSTPYTHON
317-
@unittest.expectedFailure
318316
def test_iter_string(self):
319317
self.check_for_loop(iter("abcde"), ["a", "b", "c", "d", "e"])
320318

vm/src/builtins/pystr.rs

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::ops::Range;
33
use std::string::ToString;
44
use std::{char, ffi, fmt};
55

6+
use crossbeam_utils::atomic::AtomicCell;
67
use itertools::Itertools;
78
use num_traits::ToPrimitive;
89
use unic_ucd_bidi::BidiClass;
@@ -12,7 +13,11 @@ use unicode_casing::CharExt;
1213

1314
use super::bytes::PyBytesRef;
1415
use super::dict::PyDict;
15-
use super::int::{PyInt, PyIntRef};
16+
use super::int::{try_to_primitive, PyInt, PyIntRef};
17+
use super::iter::{
18+
IterStatus,
19+
IterStatus::{Active, Exhausted},
20+
};
1621
use super::pytype::PyTypeRef;
1722
use crate::anystr::{self, adjust_indices, AnyStr, AnyStrContainer, AnyStrWrapper};
1823
use crate::exceptions::IntoPyException;
@@ -113,6 +118,7 @@ impl TryIntoRef<PyStr> for &str {
113118
pub struct PyStrIterator {
114119
string: PyStrRef,
115120
position: PyAtomic<usize>,
121+
status: AtomicCell<IterStatus>,
116122
}
117123

118124
impl PyValue for PyStrIterator {
@@ -122,20 +128,66 @@ impl PyValue for PyStrIterator {
122128
}
123129

124130
#[pyimpl(with(PyIter))]
125-
impl PyStrIterator {}
131+
impl PyStrIterator {
132+
#[pymethod(magic)]
133+
fn length_hint(&self) -> usize {
134+
match self.status.load() {
135+
Active => {
136+
let pos = self.position.load(atomic::Ordering::SeqCst);
137+
self.string.len().saturating_sub(pos)
138+
}
139+
Exhausted => 0,
140+
}
141+
}
142+
143+
#[pymethod(magic)]
144+
fn setstate(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
145+
// When we're exhausted, just return.
146+
if let Exhausted = self.status.load() {
147+
return Ok(());
148+
}
149+
let pos = state
150+
.payload::<PyInt>()
151+
.ok_or_else(|| vm.new_type_error("an integer is required.".to_owned()))?;
152+
let pos = std::cmp::min(
153+
try_to_primitive(pos.as_bigint(), vm).unwrap_or(0),
154+
self.string.len(),
155+
);
156+
self.position.store(pos, atomic::Ordering::SeqCst);
157+
Ok(())
158+
}
159+
160+
#[pymethod(magic)]
161+
fn reduce(&self, vm: &VirtualMachine) -> PyResult {
162+
let iter = vm.get_attribute(vm.builtins.clone(), "iter")?;
163+
Ok(vm.ctx.new_tuple(match self.status.load() {
164+
Exhausted => vec![iter, vm.ctx.new_tuple(vec![vm.ctx.new_str("")])],
165+
Active => vec![
166+
iter,
167+
vm.ctx.new_tuple(vec![self.string.clone().into_object()]),
168+
vm.ctx
169+
.new_int(self.position.load(atomic::Ordering::Relaxed)),
170+
],
171+
}))
172+
}
173+
}
126174

127175
impl PyIter for PyStrIterator {
128176
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult {
177+
if let Exhausted = zelf.status.load() {
178+
return Err(vm.new_stop_iteration());
179+
}
129180
let value = &*zelf.string.value;
130181
let mut start = zelf.position.load(atomic::Ordering::SeqCst);
131182
loop {
132183
if start == value.len() {
184+
zelf.status.store(Exhausted);
133185
return Err(vm.new_stop_iteration());
134186
}
135-
let ch = value[start..]
136-
.chars()
137-
.next()
138-
.ok_or_else(|| vm.new_stop_iteration())?;
187+
let ch = value[start..].chars().next().ok_or_else(|| {
188+
zelf.status.store(Exhausted);
189+
vm.new_stop_iteration()
190+
})?;
139191

140192
match zelf.position.compare_exchange_weak(
141193
start,
@@ -1123,6 +1175,7 @@ impl Iterable for PyStr {
11231175
Ok(PyStrIterator {
11241176
position: Radium::new(0),
11251177
string: zelf,
1178+
status: AtomicCell::new(Active),
11261179
}
11271180
.into_object(vm))
11281181
}

0 commit comments

Comments
 (0)