forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathiterator.rs
More file actions
112 lines (104 loc) · 3.25 KB
/
Copy pathiterator.rs
File metadata and controls
112 lines (104 loc) · 3.25 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
/*
* utilities to support iteration.
*/
use crate::{
builtins::{int, PyBaseExceptionRef, PyInt},
protocol::PyIter,
IdProtocol, PyObjectRef, PyResult, TypeProtocol, VirtualMachine,
};
use num_traits::Signed;
/*
* Helper function to retrieve the next object (or none) from an iterator.
*/
pub fn get_next_object<T>(
vm: &VirtualMachine,
iter_obj: &PyIter<T>,
) -> PyResult<Option<PyObjectRef>>
where
T: std::borrow::Borrow<PyObjectRef>,
{
let next_obj: PyResult = iter_obj.next(vm);
match next_obj {
Ok(value) => Ok(Some(value)),
Err(next_error) => {
// Check if we have stopiteration, or something else:
if next_error.isinstance(&vm.ctx.exceptions.stop_iteration) {
Ok(None)
} else {
Err(next_error)
}
}
}
}
pub fn try_map<F, R>(vm: &VirtualMachine, iter: &PyIter, cap: usize, mut f: F) -> PyResult<Vec<R>>
where
F: FnMut(PyObjectRef) -> PyResult<R>,
{
// TODO: fix extend to do this check (?), see test_extend in Lib/test/list_tests.py,
// https://github.com/python/cpython/blob/v3.9.0/Objects/listobject.c#L922-L928
if cap >= isize::max_value() as usize {
return Ok(Vec::new());
}
let mut results = Vec::with_capacity(cap);
while let Some(element) = get_next_object(vm, iter)? {
results.push(f(element)?);
}
results.shrink_to_fit();
Ok(results)
}
pub fn stop_iter_with_value(val: PyObjectRef, vm: &VirtualMachine) -> PyBaseExceptionRef {
let stop_iteration_type = vm.ctx.exceptions.stop_iteration.clone();
vm.new_exception(stop_iteration_type, vec![val])
}
pub fn stop_iter_value(vm: &VirtualMachine, exc: &PyBaseExceptionRef) -> PyObjectRef {
let args = exc.args();
vm.unwrap_or_none(args.as_slice().first().cloned())
}
pub fn length_hint(vm: &VirtualMachine, iter: PyObjectRef) -> PyResult<Option<usize>> {
if let Some(len) = vm.obj_len_opt(&iter) {
match len {
Ok(len) => return Ok(Some(len)),
Err(e) => {
if !e.isinstance(&vm.ctx.exceptions.type_error) {
return Err(e);
}
}
}
}
let hint = match vm.get_method(iter, "__length_hint__") {
Some(hint) => hint?,
None => return Ok(None),
};
let result = match vm.invoke(&hint, ()) {
Ok(res) => {
if res.is(&vm.ctx.not_implemented) {
return Ok(None);
}
res
}
Err(e) => {
return if e.isinstance(&vm.ctx.exceptions.type_error) {
Ok(None)
} else {
Err(e)
}
}
};
let result = result
.payload_if_subclass::<PyInt>(vm)
.ok_or_else(|| {
vm.new_type_error(format!(
"'{}' object cannot be interpreted as an integer",
result.class().name()
))
})?
.as_bigint();
if result.is_negative() {
return Err(vm.new_value_error("__length_hint__() should return >= 0".to_owned()));
}
let hint = int::try_to_primitive(result, vm)?;
Ok(Some(hint))
}
// pub fn seq_iter_method(obj: PyObjectRef) -> PySequenceIterator {
// PySequenceIterator::new_forward(obj)
// }