@@ -3,10 +3,7 @@ use crate::object::define_py_check;
33use crate :: pystate:: with_vm;
44use crate :: util:: FfiPtrExt ;
55use core:: ffi:: c_int;
6- use rustpython_vm:: AsObject ;
7- use rustpython_vm:: PyObjectRef ;
86use rustpython_vm:: builtins:: PyList ;
9- use rustpython_vm:: sliceable:: { SaturatedSlice , SliceableSequenceMutOp , SliceableSequenceOp } ;
107
118define_py_check ! ( fn PyList_Check , types. list_type) ;
129define_py_check ! ( exact fn PyList_CheckExact , types. list_type) ;
@@ -33,11 +30,8 @@ pub unsafe extern "C" fn PyList_Size(obj: *mut PyObject) -> isize {
3330pub unsafe extern "C" fn PyList_GetItemRef ( obj : * mut PyObject , index : isize ) -> * mut PyObject {
3431 with_vm ( |vm| {
3532 let list = unsafe { obj. assume_borrowed_and_cast :: < PyList > ( vm) } ?;
36- index
37- . try_into ( )
38- . ok ( )
39- . and_then ( |index : usize | list. borrow_vec ( ) . get ( index) . map ( ToOwned :: to_owned) )
40- . ok_or_else ( || vm. new_index_error ( format ! ( "list index out of range: {index}" ) ) )
33+ // A negative index wraps past the end and is out of range.
34+ list. get_item ( index as usize , vm)
4135 } )
4236}
4337
@@ -50,25 +44,17 @@ pub unsafe extern "C" fn PyList_SetItem(
5044 with_vm ( |vm| {
5145 let list = unsafe { list. assume_borrowed_and_cast :: < PyList > ( vm) } ?;
5246 let item = unsafe { item. assume_owned ( ) } ;
53- let index_error =
54- || vm. new_index_error ( format ! ( "list assignment index out of range: {index}" ) ) ;
55- if index < 0 {
56- return Err ( index_error ( ) ) ;
57- }
58-
59- let mut list_mut = list. borrow_vec_mut ( ) ;
60- match index - list_mut. len ( ) as isize {
61- ..0 => {
62- list_mut[ index as usize ] = item;
63- Ok ( ( ) )
64- }
47+ // A negative index wraps past the end and is out of range.
48+ let index = index as usize ;
49+ {
50+ let mut list_mut = list. borrow_vec_mut ( ) ;
6551 // This is somewhat a hack, we assume that we are populating a list right after PyList_New
66- 0 if list_mut. capacity ( ) > index as usize => {
52+ if index == list_mut. len ( ) && list_mut . capacity ( ) > index {
6753 list_mut. push ( item) ;
68- Ok ( ( ) )
54+ return Ok ( ( ) ) ;
6955 }
70- 0 .. => Err ( index_error ( ) ) ,
7156 }
57+ list. set_item ( index, item, vm)
7258 } )
7359}
7460
@@ -121,9 +107,7 @@ pub unsafe extern "C" fn PyList_GetSlice(
121107) -> * mut PyObject {
122108 with_vm ( |vm| {
123109 let list = unsafe { list. assume_borrowed_and_cast :: < PyList > ( vm) } ?;
124- let vec = list. borrow_vec ( ) ;
125- let sliced = vec. getitem_by_slice ( vm, SaturatedSlice :: from_parts ( low, high, 1 ) ) ?;
126- Ok ( vm. ctx . new_list ( sliced) )
110+ Ok ( list. get_slice ( low, high, vm) )
127111 } )
128112}
129113
@@ -136,31 +120,26 @@ pub unsafe extern "C" fn PyList_SetSlice(
136120) -> c_int {
137121 with_vm ( |vm| {
138122 let list = unsafe { list. assume_borrowed_and_cast :: < PyList > ( vm) } ?;
139- let slice = SaturatedSlice :: from_parts ( low, high, 1 ) ;
140- let mut vec = list. borrow_vec_mut ( ) ;
141-
142123 let Some ( itemlist) = ( unsafe { itemlist. assume_borrowed_or_opt ( ) } ) else {
143- vec . delitem_by_slice ( vm , slice ) ? ;
124+ list . del_slice ( low , high ) ;
144125 return Ok ( ( ) ) ;
145126 } ;
146-
147- let items: Vec < PyObjectRef > = itemlist. try_to_value ( vm) ?;
148- vec. setitem_by_slice ( vm, slice, & items)
127+ list. set_slice ( low, high, itemlist, vm)
149128 } )
150129}
151130
152131#[ unsafe( no_mangle) ]
153132pub unsafe extern "C" fn PyList_Sort ( list : * mut PyObject ) -> c_int {
154133 with_vm ( |vm| {
155134 let list = unsafe { list. assume_borrowed_and_cast :: < PyList > ( vm) } ?;
156- vm. call_method ( list. as_object ( ) , "sort" , ( ) ) ?;
157- Ok ( ( ) )
135+ list. sort ( vm)
158136 } )
159137}
160138
161139#[ cfg( test) ]
162140mod tests {
163141 use pyo3:: exceptions:: PyIndexError ;
142+ use pyo3:: ffi;
164143 use pyo3:: prelude:: * ;
165144 use pyo3:: types:: { PyList , PyListMethods } ;
166145
@@ -281,4 +260,39 @@ mod tests {
281260 assert_eq ! ( list. get_item( 2 ) . unwrap( ) . extract:: <u32 >( ) . unwrap( ) , 3 ) ;
282261 } )
283262 }
263+
264+ #[ test]
265+ fn list_del_slice ( ) {
266+ Python :: attach ( |py| {
267+ let list = PyList :: new ( py, [ 1 , 2 , 3 , 4 ] ) . unwrap ( ) ;
268+ list. del_slice ( 1 , 3 ) . unwrap ( ) ;
269+ assert_eq ! ( list. extract:: <Vec <u32 >>( ) . unwrap( ) , [ 1 , 4 ] ) ;
270+ } )
271+ }
272+
273+ #[ test]
274+ fn list_negative_indices ( ) {
275+ Python :: attach ( |py| unsafe {
276+ let list = PyList :: new ( py, [ 1 , 2 , 3 , 4 ] ) . unwrap ( ) ;
277+
278+ assert ! ( ffi:: PyList_GetItemRef ( list. as_ptr( ) , -1 ) . is_null( ) ) ;
279+ assert ! ( PyErr :: take( py) . unwrap( ) . is_instance_of:: <PyIndexError >( py) ) ;
280+
281+ let slice = Bound :: from_owned_ptr ( py, ffi:: PyList_GetSlice ( list. as_ptr ( ) , -1 , 2 ) ) ;
282+ assert_eq ! ( slice. extract:: <Vec <u32 >>( ) . unwrap( ) , [ 1 , 2 ] ) ;
283+
284+ let repl = PyList :: new ( py, [ 9 ] ) . unwrap ( ) ;
285+ assert_eq ! ( ffi:: PyList_SetSlice ( list. as_ptr( ) , -1 , 1 , repl. as_ptr( ) ) , 0 ) ;
286+ assert_eq ! ( list. extract:: <Vec <u32 >>( ) . unwrap( ) , [ 9 , 2 , 3 , 4 ] ) ;
287+ } )
288+ }
289+
290+ #[ test]
291+ fn list_set_slice_self ( ) {
292+ Python :: attach ( |py| {
293+ let list = PyList :: new ( py, [ 1 , 2 ] ) . unwrap ( ) ;
294+ list. set_slice ( 2 , 2 , list. as_any ( ) ) . unwrap ( ) ;
295+ assert_eq ! ( list. extract:: <Vec <u32 >>( ) . unwrap( ) , [ 1 , 2 , 1 , 2 ] ) ;
296+ } )
297+ }
284298}
0 commit comments