forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzip.rs
More file actions
114 lines (105 loc) · 3.94 KB
/
zip.rs
File metadata and controls
114 lines (105 loc) · 3.94 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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use super::{PyType, PyTypeRef};
use crate::{
builtins::PyTupleRef,
class::PyClassImpl,
function::{ArgIntoBool, OptionalArg, PosArgs},
protocol::{PyIter, PyIterReturn},
types::{Constructor, IterNext, IterNextIterable},
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
};
use rustpython_common::atomic::{self, PyAtomic, Radium};
#[pyclass(module = false, name = "zip")]
#[derive(Debug)]
pub struct PyZip {
iterators: Vec<PyIter>,
strict: PyAtomic<bool>,
}
impl PyPayload for PyZip {
fn class(vm: &VirtualMachine) -> &'static Py<PyType> {
vm.ctx.types.zip_type
}
}
#[derive(FromArgs)]
pub struct PyZipNewArgs {
#[pyarg(named, optional)]
strict: OptionalArg<bool>,
}
impl Constructor for PyZip {
type Args = (PosArgs<PyIter>, PyZipNewArgs);
fn py_new(cls: PyTypeRef, (iterators, args): Self::Args, vm: &VirtualMachine) -> PyResult {
let iterators = iterators.into_vec();
let strict = Radium::new(args.strict.unwrap_or(false));
PyZip { iterators, strict }
.into_ref_with_type(vm, cls)
.map(Into::into)
}
}
#[pyclass(with(IterNext, Constructor), flags(BASETYPE))]
impl PyZip {
#[pymethod(magic)]
fn reduce(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
let cls = zelf.class().to_owned();
let iterators = zelf
.iterators
.iter()
.map(|obj| obj.clone().into())
.collect::<Vec<_>>();
let tuple_iter = vm.ctx.new_tuple(iterators);
Ok(if zelf.strict.load(atomic::Ordering::Acquire) {
vm.new_tuple((cls, tuple_iter, true))
} else {
vm.new_tuple((cls, tuple_iter))
})
}
#[pymethod(magic)]
fn setstate(zelf: PyRef<Self>, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if let Ok(obj) = ArgIntoBool::try_from_object(vm, state) {
zelf.strict.store(obj.into(), atomic::Ordering::Release);
}
Ok(())
}
}
impl IterNextIterable for PyZip {}
impl IterNext for PyZip {
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
if zelf.iterators.is_empty() {
return Ok(PyIterReturn::StopIteration(None));
}
let mut next_objs = Vec::new();
for (idx, iterator) in zelf.iterators.iter().enumerate() {
let item = match iterator.next(vm)? {
PyIterReturn::Return(obj) => obj,
PyIterReturn::StopIteration(v) => {
if zelf.strict.load(atomic::Ordering::Acquire) {
if idx > 0 {
let plural = if idx == 1 { " " } else { "s 1-" };
return Err(vm.new_value_error(format!(
"zip() argument {} is shorter than argument{}{}",
idx + 1,
plural,
idx
)));
}
for (idx, iterator) in zelf.iterators[1..].iter().enumerate() {
if let PyIterReturn::Return(_obj) = iterator.next(vm)? {
let plural = if idx == 0 { " " } else { "s 1-" };
return Err(vm.new_value_error(format!(
"zip() argument {} is longer than argument{}{}",
idx + 2,
plural,
idx + 1
)));
}
}
}
return Ok(PyIterReturn::StopIteration(v));
}
};
next_objs.push(item);
}
Ok(PyIterReturn::Return(vm.ctx.new_tuple(next_objs).into()))
}
}
pub fn init(ctx: &Context) {
PyZip::extend_class(ctx, ctx.types.zip_type);
}