forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobjsequence.rs
More file actions
143 lines (137 loc) · 4.79 KB
/
objsequence.rs
File metadata and controls
143 lines (137 loc) · 4.79 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use super::super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyResult, TypeProtocol};
use super::super::vm::VirtualMachine;
use super::objbool;
use num_traits::ToPrimitive;
use std::cell::{Ref, RefMut};
use std::marker::Sized;
use std::ops::{Deref, DerefMut};
pub trait PySliceableSequence {
fn do_slice(&self, start: usize, stop: usize) -> Self;
fn do_stepped_slice(&self, start: usize, stop: usize, step: usize) -> Self;
fn len(&self) -> usize;
fn get_pos(&self, p: i32) -> usize {
if p < 0 {
self.len() - ((-p) as usize)
} else if p as usize > self.len() {
// This is for the slicing case where the end element is greater than the length of the
// sequence
self.len()
} else {
p as usize
}
}
fn get_slice_items(&self, slice: &PyObjectRef) -> Self
where
Self: Sized,
{
// TODO: we could potentially avoid this copy and use slice
match &(slice.borrow()).kind {
PyObjectKind::Slice { start, stop, step } => {
let start = match start {
&Some(start) => self.get_pos(start),
&None => 0,
};
let stop = match stop {
&Some(stop) => self.get_pos(stop),
&None => self.len() as usize,
};
match step {
&None | &Some(1) => self.do_slice(start, stop),
&Some(num) => {
if num < 0 {
unimplemented!("negative step indexing not yet supported")
};
self.do_stepped_slice(start, stop, num as usize)
}
}
}
kind => panic!("get_slice_items called with non-slice: {:?}", kind),
}
}
}
impl PySliceableSequence for Vec<PyObjectRef> {
fn do_slice(&self, start: usize, stop: usize) -> Self {
self[start..stop].to_vec()
}
fn do_stepped_slice(&self, start: usize, stop: usize, step: usize) -> Self {
self[start..stop].iter().step_by(step).cloned().collect()
}
fn len(&self) -> usize {
self.len()
}
}
pub fn get_item(
vm: &mut VirtualMachine,
sequence: &PyObjectRef,
elements: &[PyObjectRef],
subscript: PyObjectRef,
) -> PyResult {
match &(subscript.borrow()).kind {
PyObjectKind::Integer { value } => {
let value = value.to_i32().unwrap();
let pos_index = elements.to_vec().get_pos(value);
if pos_index < elements.len() {
let obj = elements[pos_index].clone();
Ok(obj)
} else {
let value_error = vm.context().exceptions.value_error.clone();
Err(vm.new_exception(value_error, "Index out of bounds!".to_string()))
}
}
PyObjectKind::Slice {
start: _,
stop: _,
step: _,
} => Ok(PyObject::new(
match &(sequence.borrow()).kind {
PyObjectKind::Sequence { elements: _ } => PyObjectKind::Sequence {
elements: elements.to_vec().get_slice_items(&subscript),
},
ref kind => panic!("sequence get_item called for non-sequence: {:?}", kind),
},
sequence.typ(),
)),
_ => Err(vm.new_type_error(format!(
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
sequence, subscript
))),
}
}
pub fn seq_equal(
vm: &mut VirtualMachine,
zelf: &Vec<PyObjectRef>,
other: &Vec<PyObjectRef>,
) -> Result<bool, PyObjectRef> {
if zelf.len() == other.len() {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
let eq = vm.call_method(&a.clone(), "__eq__", vec![b.clone()])?;
let value = objbool::boolval(vm, eq)?;
if !value {
return Ok(false);
}
}
Ok(true)
} else {
Ok(false)
}
}
pub fn get_elements<'a>(obj: &'a PyObjectRef) -> impl Deref<Target = Vec<PyObjectRef>> + 'a {
Ref::map(obj.borrow(), |x| {
if let PyObjectKind::Sequence { ref elements } = x.kind {
elements
} else {
panic!("Cannot extract elements from non-sequence");
}
})
}
pub fn get_mut_elements<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Vec<PyObjectRef>> + 'a {
RefMut::map(obj.borrow_mut(), |x| {
if let PyObjectKind::Sequence { ref mut elements } = x.kind {
elements
} else {
panic!("Cannot extract list elements from non-sequence");
// TODO: raise proper error?
// Err(vm.new_type_error("list.append is called with no list".to_string()))
}
})
}