@@ -2,7 +2,8 @@ use super::super::pyobject::{PyObject, PyObjectPayload, PyObjectRef, PyResult, T
22use super :: super :: vm:: VirtualMachine ;
33use super :: objbool;
44use super :: objint;
5- use num_traits:: ToPrimitive ;
5+ use num_bigint:: BigInt ;
6+ use num_traits:: { Signed , ToPrimitive } ;
67use std:: cell:: { Ref , RefMut } ;
78use std:: marker:: Sized ;
89use std:: ops:: { Deref , DerefMut } ;
@@ -11,45 +12,67 @@ pub trait PySliceableSequence {
1112 fn do_slice ( & self , start : usize , stop : usize ) -> Self ;
1213 fn do_stepped_slice ( & self , start : usize , stop : usize , step : usize ) -> Self ;
1314 fn len ( & self ) -> usize ;
14- fn get_pos ( & self , p : i32 ) -> usize {
15+ fn get_pos ( & self , p : i32 ) -> Option < usize > {
1516 if p < 0 {
1617 if -p as usize > self . len ( ) {
17- // return something that is out of bounds so `get_item` raises an IndexError
18- self . len ( ) + 1
18+ None
1919 } else {
20- self . len ( ) - ( ( -p) as usize )
20+ Some ( self . len ( ) - ( ( -p) as usize ) )
2121 }
22- } else if p as usize > self . len ( ) {
23- // This is for the slicing case where the end element is greater than the length of the
24- // sequence
25- self . len ( )
22+ } else if p as usize >= self . len ( ) {
23+ None
2624 } else {
27- p as usize
25+ Some ( p as usize )
2826 }
2927 }
28+
29+ fn get_slice_pos ( & self , slice_pos : & BigInt ) -> usize {
30+ if let Some ( pos) = slice_pos. to_i32 ( ) {
31+ if let Some ( index) = self . get_pos ( pos) {
32+ // within bounds
33+ return index;
34+ }
35+ }
36+
37+ if slice_pos. is_negative ( ) {
38+ 0
39+ } else {
40+ self . len ( )
41+ }
42+ }
43+
3044 fn get_slice_items ( & self , slice : & PyObjectRef ) -> Self
3145 where
3246 Self : Sized ,
3347 {
3448 // TODO: we could potentially avoid this copy and use slice
3549 match & ( slice. borrow ( ) ) . payload {
3650 PyObjectPayload :: Slice { start, stop, step } => {
37- let start = match * start {
38- Some ( start) => self . get_pos ( start) ,
39- None => 0 ,
51+ let start = if let Some ( start) = start {
52+ self . get_slice_pos ( start)
53+ } else {
54+ 0
4055 } ;
41- let stop = match * stop {
42- Some ( stop) => self . get_pos ( stop) ,
43- None => self . len ( ) as usize ,
56+ let stop = if let Some ( stop) = stop {
57+ self . get_slice_pos ( stop)
58+ } else {
59+ self . len ( )
4460 } ;
45- match * step {
46- None | Some ( 1 ) => self . do_slice ( start, stop) ,
47- Some ( num) => {
48- if num < 0 {
49- unimplemented ! ( "negative step indexing not yet supported" )
50- } ;
51- self . do_stepped_slice ( start, stop, num as usize )
61+ if let Some ( step) = step {
62+ match step. to_i32 ( ) {
63+ Some ( 1 ) => self . do_slice ( start, stop) ,
64+ Some ( num) => self . do_stepped_slice ( start, stop, num as usize ) ,
65+ None => self . do_slice (
66+ start,
67+ if start == self . len ( ) {
68+ start
69+ } else {
70+ start + 1
71+ } ,
72+ ) ,
5273 }
74+ } else {
75+ self . do_slice ( start, stop)
5376 }
5477 }
5578 payload => panic ! ( "get_slice_items called with non-slice: {:?}" , payload) ,
@@ -78,8 +101,7 @@ pub fn get_item(
78101 match & ( subscript. borrow ( ) ) . payload {
79102 PyObjectPayload :: Integer { value } => match value. to_i32 ( ) {
80103 Some ( value) => {
81- let pos_index = elements. to_vec ( ) . get_pos ( value) ;
82- if pos_index < elements. len ( ) {
104+ if let Some ( pos_index) = elements. to_vec ( ) . get_pos ( value) {
83105 let obj = elements[ pos_index] . clone ( ) ;
84106 Ok ( obj)
85107 } else {
0 commit comments