Skip to content

Commit 78e9f01

Browse files
Merge pull request RustPython#1323 from corona10/dropwhile
itertools.dropwhile: Implement itertools.dropwhile
2 parents e9820c1 + 44ceaa8 commit 78e9f01

File tree

3 files changed

+78
-4
lines changed

3 files changed

+78
-4
lines changed

tests/snippets/stdlib_itertools.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,4 +200,13 @@ def assert_matches_seq(it, seq):
200200
assert None == next(it)
201201
assert False == next(it)
202202
assert [] == next(it)
203-
assert {} == next(it)
203+
assert {} == next(it)
204+
205+
206+
# itertools.dropwhile
207+
it = itertools.dropwhile(lambda x: x<5, [1,4,6,4,1])
208+
assert 6 == next(it)
209+
assert 4 == next(it)
210+
assert 1 == next(it)
211+
with assertRaises(StopIteration):
212+
next(it)

vm/src/pyobject.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ where
670670
}
671671
}
672672

673-
#[derive(Clone)]
673+
#[derive(Clone, Debug)]
674674
pub struct PyCallable {
675675
obj: PyObjectRef,
676676
}

vm/src/stdlib/itertools.rs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::cell::RefCell;
1+
use std::cell::{Cell, RefCell};
22
use std::cmp::Ordering;
33
use std::ops::{AddAssign, SubAssign};
44

@@ -12,7 +12,7 @@ use crate::obj::objint::{PyInt, PyIntRef};
1212
use crate::obj::objiter::{call_next, get_iter, new_stop_iteration};
1313
use crate::obj::objtype;
1414
use crate::obj::objtype::PyClassRef;
15-
use crate::pyobject::{IdProtocol, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue};
15+
use crate::pyobject::{IdProtocol, PyCallable, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue};
1616
use crate::vm::VirtualMachine;
1717

1818
#[pyclass(name = "chain")]
@@ -290,6 +290,67 @@ impl PyItertoolsTakewhile {
290290
}
291291
}
292292

293+
#[pyclass]
294+
#[derive(Debug)]
295+
struct PyItertoolsDropwhile {
296+
predicate: PyCallable,
297+
iterable: PyObjectRef,
298+
start_flag: Cell<bool>,
299+
}
300+
301+
impl PyValue for PyItertoolsDropwhile {
302+
fn class(vm: &VirtualMachine) -> PyClassRef {
303+
vm.class("itertools", "dropwhile")
304+
}
305+
}
306+
307+
type PyItertoolsDropwhileRef = PyRef<PyItertoolsDropwhile>;
308+
309+
#[pyimpl]
310+
impl PyItertoolsDropwhile {
311+
#[pymethod(name = "__new__")]
312+
#[allow(clippy::new_ret_no_self)]
313+
fn new(
314+
cls: PyClassRef,
315+
predicate: PyCallable,
316+
iterable: PyObjectRef,
317+
vm: &VirtualMachine,
318+
) -> PyResult<PyItertoolsDropwhileRef> {
319+
let iter = get_iter(vm, &iterable)?;
320+
321+
PyItertoolsDropwhile {
322+
predicate,
323+
iterable: iter,
324+
start_flag: Cell::new(false),
325+
}
326+
.into_ref_with_type(vm, cls)
327+
}
328+
329+
#[pymethod(name = "__next__")]
330+
fn next(&self, vm: &VirtualMachine) -> PyResult {
331+
let predicate = &self.predicate;
332+
let iterable = &self.iterable;
333+
334+
if !self.start_flag.get() {
335+
loop {
336+
let obj = call_next(vm, iterable)?;
337+
let pred = predicate.clone();
338+
let pred_value = vm.invoke(&pred.into_object(), vec![obj.clone()])?;
339+
if !objbool::boolval(vm, pred_value)? {
340+
self.start_flag.set(true);
341+
return Ok(obj);
342+
}
343+
}
344+
}
345+
call_next(vm, iterable)
346+
}
347+
348+
#[pymethod(name = "__iter__")]
349+
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
350+
zelf
351+
}
352+
}
353+
293354
#[pyclass(name = "islice")]
294355
#[derive(Debug)]
295356
struct PyItertoolsIslice {
@@ -484,6 +545,9 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
484545
let count = ctx.new_class("count", ctx.object());
485546
PyItertoolsCount::extend_class(ctx, &count);
486547

548+
let dropwhile = ctx.new_class("dropwhile", ctx.object());
549+
PyItertoolsDropwhile::extend_class(ctx, &dropwhile);
550+
487551
let repeat = ctx.new_class("repeat", ctx.object());
488552
PyItertoolsRepeat::extend_class(ctx, &repeat);
489553

@@ -500,6 +564,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
500564
py_module!(vm, "itertools", {
501565
"chain" => chain,
502566
"count" => count,
567+
"dropwhile" => dropwhile,
503568
"repeat" => repeat,
504569
"starmap" => starmap,
505570
"takewhile" => takewhile,

0 commit comments

Comments
 (0)