Skip to content

Commit dd5f9e3

Browse files
committed
Refactor get_item for sequences
1 parent 699c801 commit dd5f9e3

File tree

4 files changed

+72
-66
lines changed

4 files changed

+72
-66
lines changed

vm/src/obj/objlist.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::pyobject::{
1818
PyResult, PyValue, TryFromObject, TypeProtocol,
1919
};
2020
use crate::sequence::{self, SimpleSeq};
21-
use crate::sliceable::{get_item, PySliceableSequence, PySliceableSequenceMut, SequenceIndex};
21+
use crate::sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex};
2222
use crate::slots::{Comparable, Hashable, PyComparisonOp, Unhashable};
2323
use crate::vm::{ReprGuard, VirtualMachine};
2424

@@ -190,12 +190,11 @@ impl PyList {
190190

191191
#[pymethod(name = "__getitem__")]
192192
fn getitem(zelf: PyRef<Self>, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
193-
Ok(
194-
match get_item(vm, zelf.as_object(), &zelf.borrow_value(), needle)? {
195-
Either::A(obj) => obj,
196-
Either::B(vec) => vm.ctx.new_list(vec),
197-
},
198-
)
193+
let result = match zelf.borrow_value().get_item(vm, needle, "list")? {
194+
Either::A(obj) => obj,
195+
Either::B(vec) => vm.ctx.new_list(vec),
196+
};
197+
Ok(result)
199198
}
200199

201200
#[pymethod(name = "__iter__")]

vm/src/obj/objstr.rs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ use crate::exceptions::IntoPyException;
2222
use crate::format::{FormatSpec, FormatString, FromTemplate};
2323
use crate::function::{OptionalArg, OptionalOption, PyFuncArgs};
2424
use crate::pyobject::{
25-
BorrowValue, IdProtocol, IntoPyObject, ItemProtocol, PyClassImpl, PyComparisonValue, PyContext,
26-
PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TryIntoRef, TypeProtocol,
25+
BorrowValue, Either, IdProtocol, IntoPyObject, ItemProtocol, PyClassImpl, PyComparisonValue,
26+
PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TryIntoRef,
27+
TypeProtocol,
2728
};
28-
use crate::sliceable::{PySliceableSequence, SequenceIndex};
29+
use crate::sliceable::PySliceableSequence;
2930
use crate::slots::{Comparable, Hashable, PyComparisonOp};
3031
use crate::VirtualMachine;
3132
use rustpython_common::hash;
@@ -228,26 +229,12 @@ impl PyStr {
228229
}
229230

230231
#[pymethod(name = "__getitem__")]
231-
fn getitem(&self, needle: SequenceIndex, vm: &VirtualMachine) -> PyResult {
232-
match needle {
233-
SequenceIndex::Int(pos) => {
234-
let index: usize = if pos.is_negative() {
235-
(self.value.chars().count() as isize + pos) as usize
236-
} else {
237-
pos.abs() as usize
238-
};
239-
240-
if let Some(character) = self.value.chars().nth(index) {
241-
Ok(vm.ctx.new_str(character.to_string()))
242-
} else {
243-
Err(vm.new_index_error("string index out of range".to_owned()))
244-
}
245-
}
246-
SequenceIndex::Slice(slice) => {
247-
let string = self.get_slice_items(vm, &slice)?;
248-
Ok(vm.ctx.new_str(string))
249-
}
250-
}
232+
fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
233+
let s = match self.get_item(vm, needle, "string")? {
234+
Either::A(ch) => ch.to_string(),
235+
Either::B(s) => s,
236+
};
237+
Ok(vm.ctx.new_str(s))
251238
}
252239

253240
pub(crate) fn hash(&self, vm: &VirtualMachine) -> hash::PyHash {
@@ -1172,8 +1159,13 @@ pub fn borrow_value(obj: &PyObjectRef) -> &str {
11721159
}
11731160

11741161
impl PySliceableSequence for PyStr {
1162+
type Item = char;
11751163
type Sliced = String;
11761164

1165+
fn do_get(&self, index: usize) -> Self::Item {
1166+
self.value.chars().nth(index).unwrap()
1167+
}
1168+
11771169
fn do_slice(&self, range: Range<usize>) -> Self::Sliced {
11781170
self.value
11791171
.chars()

vm/src/obj/objtuple.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::pyobject::{
99
PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
1010
};
1111
use crate::sequence::{self, SimpleSeq};
12-
use crate::sliceable::get_item;
12+
use crate::sliceable::PySliceableSequence;
1313
use crate::slots::{Comparable, Hashable, PyComparisonOp};
1414
use crate::vm::{ReprGuard, VirtualMachine};
1515
use rustpython_common::hash::PyHash;
@@ -184,12 +184,11 @@ impl PyTuple {
184184

185185
#[pymethod(name = "__getitem__")]
186186
fn getitem(zelf: PyRef<Self>, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
187-
Ok(
188-
match get_item(vm, zelf.as_object(), &zelf.elements, needle)? {
189-
Either::A(obj) => obj,
190-
Either::B(vec) => vm.ctx.new_tuple(vec),
191-
},
192-
)
187+
let result = match zelf.elements.as_ref().get_item(vm, needle, "tuple")? {
188+
Either::A(obj) => obj,
189+
Either::B(vec) => vm.ctx.new_tuple(vec),
190+
};
191+
Ok(result)
193192
}
194193

195194
#[pymethod(name = "index")]

vm/src/sliceable.rs

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,10 @@ impl<T: Clone> PySliceableSequenceMut for Vec<T> {
240240
}
241241

242242
pub trait PySliceableSequence {
243+
type Item;
243244
type Sliced;
244245

246+
fn do_get(&self, index: usize) -> Self::Item;
245247
fn do_slice(&self, range: Range<usize>) -> Self::Sliced;
246248
fn do_slice_reverse(&self, range: Range<usize>) -> Self::Sliced;
247249
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self::Sliced;
@@ -332,25 +334,53 @@ pub trait PySliceableSequence {
332334
}
333335
}
334336
}
337+
338+
fn get_item(
339+
&self,
340+
vm: &VirtualMachine,
341+
needle: PyObjectRef,
342+
owner_type: &'static str,
343+
) -> PyResult<Either<Self::Item, Self::Sliced>> {
344+
let needle = SequenceIndex::try_from_object_for(vm, needle, owner_type)?;
345+
match needle {
346+
SequenceIndex::Int(value) => {
347+
let pos_index = self.wrap_index(value).ok_or_else(|| {
348+
vm.new_index_error(format!("{} index out of range", owner_type))
349+
})?;
350+
Ok(Either::A(self.do_get(pos_index)))
351+
}
352+
SequenceIndex::Slice(slice) => Ok(Either::B(self.get_slice_items(vm, &slice)?)),
353+
}
354+
}
335355
}
336356

337357
impl<T: Clone> PySliceableSequence for [T] {
358+
type Item = T;
338359
type Sliced = Vec<T>;
339360

361+
#[inline]
362+
fn do_get(&self, index: usize) -> Self::Item {
363+
self[index].clone()
364+
}
365+
366+
#[inline]
340367
fn do_slice(&self, range: Range<usize>) -> Self::Sliced {
341368
self[range].to_vec()
342369
}
343370

371+
#[inline]
344372
fn do_slice_reverse(&self, range: Range<usize>) -> Self::Sliced {
345373
let mut slice = self[range].to_vec();
346374
slice.reverse();
347375
slice
348376
}
349377

378+
#[inline]
350379
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self::Sliced {
351380
self[range].iter().step_by(step).cloned().collect()
352381
}
353382

383+
#[inline]
354384
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self::Sliced {
355385
self[range].iter().rev().step_by(step).cloned().collect()
356386
}
@@ -376,8 +406,12 @@ pub enum SequenceIndex {
376406
Slice(PySliceRef),
377407
}
378408

379-
impl TryFromObject for SequenceIndex {
380-
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
409+
impl SequenceIndex {
410+
fn try_from_object_for(
411+
vm: &VirtualMachine,
412+
obj: PyObjectRef,
413+
owner_type: &'static str,
414+
) -> PyResult<Self> {
381415
match_class!(match obj {
382416
i @ PyInt => i
383417
.borrow_value()
@@ -387,13 +421,20 @@ impl TryFromObject for SequenceIndex {
387421
.new_index_error("cannot fit 'int' into an index-sized integer".to_owned())),
388422
s @ PySlice => Ok(SequenceIndex::Slice(s)),
389423
obj => Err(vm.new_type_error(format!(
390-
"sequence indices be integers or slices, not {}",
391-
obj.class(),
424+
"{} indices must be integers or slices, not {}",
425+
owner_type,
426+
obj.lease_class().name,
392427
))),
393428
})
394429
}
395430
}
396431

432+
impl TryFromObject for SequenceIndex {
433+
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
434+
Self::try_from_object_for(vm, obj, "sequence")
435+
}
436+
}
437+
397438
/// Get the index into a sequence like type. Get it from a python integer
398439
/// object, accounting for negative index, and out of bounds issues.
399440
// pub fn get_sequence_index(vm: &VirtualMachine, index: &PyIntRef, length: usize) -> PyResult<usize> {
@@ -455,31 +496,6 @@ pub(crate) fn saturate_index(p: isize, len: usize) -> usize {
455496
// start..stop
456497
// }
457498

458-
pub fn get_item(
459-
vm: &VirtualMachine,
460-
sequence: &PyObjectRef,
461-
elements: &[PyObjectRef],
462-
subscript: PyObjectRef,
463-
) -> PyResult<Either<PyObjectRef, Vec<PyObjectRef>>> {
464-
if let Some(i) = subscript.payload::<PyInt>() {
465-
let value = i.borrow_value().to_isize().ok_or_else(|| {
466-
vm.new_index_error("cannot fit 'int' into an index-sized integer".to_owned())
467-
})?;
468-
let pos_index = elements
469-
.wrap_index(value)
470-
.ok_or_else(|| vm.new_index_error("Index out of bounds!".to_owned()))?;
471-
Ok(Either::A(elements[pos_index].clone()))
472-
} else {
473-
let slice = subscript.payload::<PySlice>().ok_or_else(|| {
474-
vm.new_type_error(format!(
475-
"{} indices must be integers or slices",
476-
sequence.lease_class().name
477-
))
478-
})?;
479-
Ok(Either::B(elements.get_slice_items(vm, slice)?))
480-
}
481-
}
482-
483499
//Check if given arg could be used with PySliceableSequence.saturate_range()
484500
// pub fn is_valid_slice_arg(
485501
// arg: OptionalArg<PyObjectRef>,

0 commit comments

Comments
 (0)