forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilter.rs
More file actions
74 lines (67 loc) · 2.27 KB
/
filter.rs
File metadata and controls
74 lines (67 loc) · 2.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use super::{PyType, PyTypeRef};
use crate::{
class::PyClassImpl,
protocol::{PyIter, PyIterReturn},
types::{Constructor, IterNext, IterNextIterable},
Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
};
#[pyclass(module = false, name = "filter")]
#[derive(Debug)]
pub struct PyFilter {
predicate: PyObjectRef,
iterator: PyIter,
}
impl PyPayload for PyFilter {
fn class(vm: &VirtualMachine) -> &'static Py<PyType> {
vm.ctx.types.filter_type
}
}
impl Constructor for PyFilter {
type Args = (PyObjectRef, PyIter);
fn py_new(cls: PyTypeRef, (function, iterator): Self::Args, vm: &VirtualMachine) -> PyResult {
Self {
predicate: function,
iterator,
}
.into_ref_with_type(vm, cls)
.map(Into::into)
}
}
#[pyclass(with(IterNext, Constructor), flags(BASETYPE))]
impl PyFilter {
#[pymethod(magic)]
fn reduce(&self, vm: &VirtualMachine) -> (PyTypeRef, (PyObjectRef, PyIter)) {
(
vm.ctx.types.filter_type.to_owned(),
(self.predicate.clone(), self.iterator.clone()),
)
}
}
impl IterNextIterable for PyFilter {}
impl IterNext for PyFilter {
fn next(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
let predicate = &zelf.predicate;
loop {
let next_obj = match zelf.iterator.next(vm)? {
PyIterReturn::Return(obj) => obj,
PyIterReturn::StopIteration(v) => return Ok(PyIterReturn::StopIteration(v)),
};
let predicate_value = if vm.is_none(predicate) {
next_obj.clone()
} else {
// the predicate itself can raise StopIteration which does stop the filter
// iteration
match PyIterReturn::from_pyresult(vm.invoke(predicate, (next_obj.clone(),)), vm)? {
PyIterReturn::Return(obj) => obj,
PyIterReturn::StopIteration(v) => return Ok(PyIterReturn::StopIteration(v)),
}
};
if predicate_value.try_to_bool(vm)? {
return Ok(PyIterReturn::Return(next_obj));
}
}
}
}
pub fn init(context: &Context) {
PyFilter::extend_class(context, context.types.filter_type);
}