@@ -66,23 +66,38 @@ impl PyList {
66
66
self . len ( ) == 0
67
67
}
68
68
69
- /// Gets the item at the specified index.
70
- ///
71
- /// Panics if the index is out of range.
72
- pub fn get_item ( & self , index : isize ) -> & PyAny {
73
- assert ! ( index >= 0 && index < self . len( ) as isize ) ;
69
+ /// Gets the list item at the specified index.
70
+ /// # Example
71
+ /// ```
72
+ /// use pyo3::{prelude::*, types::PyList};
73
+ /// Python::with_gil(|py| {
74
+ /// let list = PyList::new(py, &[2, 3, 5, 7]);
75
+ /// let obj = list.get_item(0);
76
+ /// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
77
+ /// });
78
+ /// ```
79
+ pub fn get_item ( & self , index : usize ) -> PyResult < & PyAny > {
74
80
unsafe {
75
- #[ cfg( not( Py_LIMITED_API ) ) ]
76
- let ptr = ffi:: PyList_GET_ITEM ( self . as_ptr ( ) , index as Py_ssize_t ) ;
77
- #[ cfg( Py_LIMITED_API ) ]
78
- let ptr = ffi:: PyList_GetItem ( self . as_ptr ( ) , index as Py_ssize_t ) ;
79
-
81
+ let item = ffi:: PyList_GetItem ( self . as_ptr ( ) , index as Py_ssize_t ) ;
80
82
// PyList_GetItem return borrowed ptr; must make owned for safety (see #890).
81
- ffi:: Py_INCREF ( ptr ) ;
82
- self . py ( ) . from_owned_ptr ( ptr )
83
+ ffi:: Py_INCREF ( item ) ;
84
+ self . py ( ) . from_owned_ptr_or_err ( item )
83
85
}
84
86
}
85
87
88
+ /// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
89
+ ///
90
+ /// # Safety
91
+ ///
92
+ /// Caller must verify that the index is within the bounds of the list.
93
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
94
+ pub unsafe fn get_item_unchecked ( & self , index : usize ) -> & PyAny {
95
+ let item = ffi:: PyList_GET_ITEM ( self . as_ptr ( ) , index as Py_ssize_t ) ;
96
+ // PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890).
97
+ ffi:: Py_INCREF ( item) ;
98
+ self . py ( ) . from_owned_ptr ( item)
99
+ }
100
+
86
101
/// Sets the item at the specified index.
87
102
///
88
103
/// Panics if the index is out of range.
@@ -142,16 +157,19 @@ impl PyList {
142
157
/// Used by `PyList::iter()`.
143
158
pub struct PyListIterator < ' a > {
144
159
list : & ' a PyList ,
145
- index : isize ,
160
+ index : usize ,
146
161
}
147
162
148
163
impl < ' a > Iterator for PyListIterator < ' a > {
149
164
type Item = & ' a PyAny ;
150
165
151
166
#[ inline]
152
167
fn next ( & mut self ) -> Option < & ' a PyAny > {
153
- if self . index < self . list . len ( ) as isize {
154
- let item = self . list . get_item ( self . index ) ;
168
+ if self . index < self . list . len ( ) {
169
+ #[ cfg( any( Py_LIMITED_API , PyPy ) ) ]
170
+ let item = self . list . get_item ( self . index ) . expect ( "tuple.get failed" ) ;
171
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
172
+ let item = unsafe { self . list . get_item_unchecked ( self . index ) } ;
155
173
self . index += 1 ;
156
174
Some ( item)
157
175
} else {
@@ -164,8 +182,8 @@ impl<'a> Iterator for PyListIterator<'a> {
164
182
let len = self . list . len ( ) ;
165
183
166
184
(
167
- len. saturating_sub ( self . index as usize ) ,
168
- Some ( len. saturating_sub ( self . index as usize ) ) ,
185
+ len. saturating_sub ( self . index ) ,
186
+ Some ( len. saturating_sub ( self . index ) ) ,
169
187
)
170
188
}
171
189
}
@@ -216,10 +234,10 @@ mod tests {
216
234
fn test_new ( ) {
217
235
Python :: with_gil ( |py| {
218
236
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
219
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
220
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
221
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
222
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
237
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
238
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
239
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
240
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
223
241
} ) ;
224
242
}
225
243
@@ -235,19 +253,10 @@ mod tests {
235
253
fn test_get_item ( ) {
236
254
Python :: with_gil ( |py| {
237
255
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
238
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
239
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
240
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
241
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
242
- } ) ;
243
- }
244
-
245
- #[ test]
246
- #[ should_panic]
247
- fn test_get_item_invalid ( ) {
248
- Python :: with_gil ( |py| {
249
- let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
250
- list. get_item ( -1 ) ;
256
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
257
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
258
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
259
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
251
260
} ) ;
252
261
}
253
262
@@ -256,9 +265,9 @@ mod tests {
256
265
Python :: with_gil ( |py| {
257
266
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
258
267
let val = 42i32 . to_object ( py) ;
259
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
268
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
260
269
list. set_item ( 0 , val) . unwrap ( ) ;
261
- assert_eq ! ( 42 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
270
+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
262
271
} ) ;
263
272
}
264
273
@@ -286,11 +295,11 @@ mod tests {
286
295
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
287
296
let val = 42i32 . to_object ( py) ;
288
297
assert_eq ! ( 4 , list. len( ) ) ;
289
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
298
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
290
299
list. insert ( 0 , val) . unwrap ( ) ;
291
300
assert_eq ! ( 5 , list. len( ) ) ;
292
- assert_eq ! ( 42 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
293
- assert_eq ! ( 2 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
301
+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
302
+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
294
303
} ) ;
295
304
}
296
305
@@ -315,8 +324,8 @@ mod tests {
315
324
Python :: with_gil ( |py| {
316
325
let list = PyList :: new ( py, & [ 2 ] ) ;
317
326
list. append ( 3 ) . unwrap ( ) ;
318
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
319
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
327
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
328
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
320
329
} ) ;
321
330
}
322
331
@@ -393,15 +402,15 @@ mod tests {
393
402
Python :: with_gil ( |py| {
394
403
let v = vec ! [ 7 , 3 , 2 , 5 ] ;
395
404
let list = PyList :: new ( py, & v) ;
396
- assert_eq ! ( 7 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
397
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
398
- assert_eq ! ( 2 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
399
- assert_eq ! ( 5 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
405
+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
406
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
407
+ assert_eq ! ( 2 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
408
+ assert_eq ! ( 5 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
400
409
list. sort ( ) . unwrap ( ) ;
401
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
402
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
403
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
404
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
410
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
411
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
412
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
413
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
405
414
} ) ;
406
415
}
407
416
@@ -410,15 +419,15 @@ mod tests {
410
419
Python :: with_gil ( |py| {
411
420
let v = vec ! [ 2 , 3 , 5 , 7 ] ;
412
421
let list = PyList :: new ( py, & v) ;
413
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
414
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
415
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
416
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
422
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
423
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
424
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
425
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
417
426
list. reverse ( ) . unwrap ( ) ;
418
- assert_eq ! ( 7 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
419
- assert_eq ! ( 5 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
420
- assert_eq ! ( 3 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
421
- assert_eq ! ( 2 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
427
+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
428
+ assert_eq ! ( 5 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
429
+ assert_eq ! ( 3 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
430
+ assert_eq ! ( 2 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
422
431
} ) ;
423
432
}
424
433
@@ -427,8 +436,49 @@ mod tests {
427
436
Python :: with_gil ( |py| {
428
437
let array: PyObject = [ 1 , 2 ] . into_py ( py) ;
429
438
let list = <PyList as PyTryFrom >:: try_from ( array. as_ref ( py) ) . unwrap ( ) ;
430
- assert_eq ! ( 1 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
431
- assert_eq ! ( 2 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
439
+ assert_eq ! ( 1 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
440
+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
441
+ } ) ;
442
+ }
443
+
444
+ #[ test]
445
+ fn test_list_get_item_invalid_index ( ) {
446
+ Python :: with_gil ( |py| {
447
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
448
+ let obj = list. get_item ( 5 ) ;
449
+ assert ! ( obj. is_err( ) ) ;
450
+ assert_eq ! (
451
+ obj. unwrap_err( ) . to_string( ) ,
452
+ "IndexError: list index out of range"
453
+ ) ;
454
+ } ) ;
455
+ }
456
+
457
+ #[ test]
458
+ fn test_list_get_item_sanity ( ) {
459
+ Python :: with_gil ( |py| {
460
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
461
+ let obj = list. get_item ( 0 ) ;
462
+ assert_eq ! ( obj. unwrap( ) . extract:: <i32 >( ) . unwrap( ) , 2 ) ;
463
+ } ) ;
464
+ }
465
+
466
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
467
+ #[ test]
468
+ fn test_list_get_item_unchecked_sanity ( ) {
469
+ Python :: with_gil ( |py| {
470
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
471
+ let obj = unsafe { list. get_item_unchecked ( 0 ) } ;
472
+ assert_eq ! ( obj. extract:: <i32 >( ) . unwrap( ) , 2 ) ;
473
+ } ) ;
474
+ }
475
+
476
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
477
+ #[ test]
478
+ fn test_list_get_item_unchecked_invalid_index ( ) {
479
+ Python :: with_gil ( |py| {
480
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
481
+ unsafe { list. get_item_unchecked ( 5 ) } ;
432
482
} ) ;
433
483
}
434
484
}
0 commit comments