@@ -66,23 +66,39 @@ 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_XINCREF ( 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
+ #[ cfg_attr( docsrs, doc( cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ) ) ]
95
+ pub unsafe fn get_item_unchecked ( & self , index : usize ) -> & PyAny {
96
+ let item = ffi:: PyList_GET_ITEM ( self . as_ptr ( ) , index as Py_ssize_t ) ;
97
+ // PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890).
98
+ ffi:: Py_XINCREF ( item) ;
99
+ self . py ( ) . from_owned_ptr ( item)
100
+ }
101
+
86
102
/// Takes the slice `self[low:high]` and returns it as a new list.
87
103
///
88
104
/// Indices must be nonnegative, and out-of-range indices are clipped to
@@ -163,16 +179,19 @@ impl PyList {
163
179
/// Used by `PyList::iter()`.
164
180
pub struct PyListIterator < ' a > {
165
181
list : & ' a PyList ,
166
- index : isize ,
182
+ index : usize ,
167
183
}
168
184
169
185
impl < ' a > Iterator for PyListIterator < ' a > {
170
186
type Item = & ' a PyAny ;
171
187
172
188
#[ inline]
173
189
fn next ( & mut self ) -> Option < & ' a PyAny > {
174
- if self . index < self . list . len ( ) as isize {
175
- let item = self . list . get_item ( self . index ) ;
190
+ if self . index < self . list . len ( ) {
191
+ #[ cfg( any( Py_LIMITED_API , PyPy ) ) ]
192
+ let item = self . list . get_item ( self . index ) . expect ( "tuple.get failed" ) ;
193
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
194
+ let item = unsafe { self . list . get_item_unchecked ( self . index ) } ;
176
195
self . index += 1 ;
177
196
Some ( item)
178
197
} else {
@@ -185,8 +204,8 @@ impl<'a> Iterator for PyListIterator<'a> {
185
204
let len = self . list . len ( ) ;
186
205
187
206
(
188
- len. saturating_sub ( self . index as usize ) ,
189
- Some ( len. saturating_sub ( self . index as usize ) ) ,
207
+ len. saturating_sub ( self . index ) ,
208
+ Some ( len. saturating_sub ( self . index ) ) ,
190
209
)
191
210
}
192
211
}
@@ -237,10 +256,10 @@ mod tests {
237
256
fn test_new ( ) {
238
257
Python :: with_gil ( |py| {
239
258
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
240
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
241
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
242
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
243
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
259
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
260
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
261
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
262
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
244
263
} ) ;
245
264
}
246
265
@@ -256,19 +275,10 @@ mod tests {
256
275
fn test_get_item ( ) {
257
276
Python :: with_gil ( |py| {
258
277
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
259
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
260
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
261
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
262
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
263
- } ) ;
264
- }
265
-
266
- #[ test]
267
- #[ should_panic]
268
- fn test_get_item_invalid ( ) {
269
- Python :: with_gil ( |py| {
270
- let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
271
- list. get_item ( -1 ) ;
278
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
279
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
280
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
281
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
272
282
} ) ;
273
283
}
274
284
@@ -289,9 +299,9 @@ mod tests {
289
299
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
290
300
let val = 42i32 . to_object ( py) ;
291
301
let val2 = 42i32 . to_object ( py) ;
292
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
302
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
293
303
list. set_item ( 0 , val) . unwrap ( ) ;
294
- assert_eq ! ( 42 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
304
+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
295
305
assert ! ( list. set_item( 10 , val2) . is_err( ) ) ;
296
306
} ) ;
297
307
}
@@ -321,13 +331,13 @@ mod tests {
321
331
let val = 42i32 . to_object ( py) ;
322
332
let val2 = 43i32 . to_object ( py) ;
323
333
assert_eq ! ( 4 , list. len( ) ) ;
324
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
334
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
325
335
list. insert ( 0 , val) . unwrap ( ) ;
326
336
list. insert ( 1000 , val2) . unwrap ( ) ;
327
337
assert_eq ! ( 6 , list. len( ) ) ;
328
- assert_eq ! ( 42 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
329
- assert_eq ! ( 2 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
330
- assert_eq ! ( 43 , list. get_item( 5 ) . extract:: <i32 >( ) . unwrap( ) ) ;
338
+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
339
+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
340
+ assert_eq ! ( 43 , list. get_item( 5 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
331
341
} ) ;
332
342
}
333
343
@@ -352,8 +362,8 @@ mod tests {
352
362
Python :: with_gil ( |py| {
353
363
let list = PyList :: new ( py, & [ 2 ] ) ;
354
364
list. append ( 3 ) . unwrap ( ) ;
355
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
356
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
365
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
366
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
357
367
} ) ;
358
368
}
359
369
@@ -430,15 +440,15 @@ mod tests {
430
440
Python :: with_gil ( |py| {
431
441
let v = vec ! [ 7 , 3 , 2 , 5 ] ;
432
442
let list = PyList :: new ( py, & v) ;
433
- assert_eq ! ( 7 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
434
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
435
- assert_eq ! ( 2 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
436
- assert_eq ! ( 5 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
443
+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
444
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
445
+ assert_eq ! ( 2 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
446
+ assert_eq ! ( 5 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
437
447
list. sort ( ) . unwrap ( ) ;
438
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
439
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
440
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
441
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
448
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
449
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
450
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
451
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
442
452
} ) ;
443
453
}
444
454
@@ -447,15 +457,15 @@ mod tests {
447
457
Python :: with_gil ( |py| {
448
458
let v = vec ! [ 2 , 3 , 5 , 7 ] ;
449
459
let list = PyList :: new ( py, & v) ;
450
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
451
- assert_eq ! ( 3 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
452
- assert_eq ! ( 5 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
453
- assert_eq ! ( 7 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
460
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
461
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
462
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
463
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
454
464
list. reverse ( ) . unwrap ( ) ;
455
- assert_eq ! ( 7 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
456
- assert_eq ! ( 5 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
457
- assert_eq ! ( 3 , list. get_item( 2 ) . extract:: <i32 >( ) . unwrap( ) ) ;
458
- assert_eq ! ( 2 , list. get_item( 3 ) . extract:: <i32 >( ) . unwrap( ) ) ;
465
+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
466
+ assert_eq ! ( 5 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
467
+ assert_eq ! ( 3 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
468
+ assert_eq ! ( 2 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
459
469
} ) ;
460
470
}
461
471
@@ -464,8 +474,40 @@ mod tests {
464
474
Python :: with_gil ( |py| {
465
475
let array: PyObject = [ 1 , 2 ] . into_py ( py) ;
466
476
let list = <PyList as PyTryFrom >:: try_from ( array. as_ref ( py) ) . unwrap ( ) ;
467
- assert_eq ! ( 1 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
468
- assert_eq ! ( 2 , list. get_item( 1 ) . extract:: <i32 >( ) . unwrap( ) ) ;
477
+ assert_eq ! ( 1 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
478
+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
479
+ } ) ;
480
+ }
481
+
482
+ #[ test]
483
+ fn test_list_get_item_invalid_index ( ) {
484
+ Python :: with_gil ( |py| {
485
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
486
+ let obj = list. get_item ( 5 ) ;
487
+ assert ! ( obj. is_err( ) ) ;
488
+ assert_eq ! (
489
+ obj. unwrap_err( ) . to_string( ) ,
490
+ "IndexError: list index out of range"
491
+ ) ;
492
+ } ) ;
493
+ }
494
+
495
+ #[ test]
496
+ fn test_list_get_item_sanity ( ) {
497
+ Python :: with_gil ( |py| {
498
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
499
+ let obj = list. get_item ( 0 ) ;
500
+ assert_eq ! ( obj. unwrap( ) . extract:: <i32 >( ) . unwrap( ) , 2 ) ;
501
+ } ) ;
502
+ }
503
+
504
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
505
+ #[ test]
506
+ fn test_list_get_item_unchecked_sanity ( ) {
507
+ Python :: with_gil ( |py| {
508
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
509
+ let obj = unsafe { list. get_item_unchecked ( 0 ) } ;
510
+ assert_eq ! ( obj. extract:: <i32 >( ) . unwrap( ) , 2 ) ;
469
511
} ) ;
470
512
}
471
513
}
0 commit comments