@@ -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
/// Sets the item at the specified index.
87
103
///
88
104
/// Panics if the index is out of range.
@@ -142,16 +158,19 @@ impl PyList {
142
158
/// Used by `PyList::iter()`.
143
159
pub struct PyListIterator < ' a > {
144
160
list : & ' a PyList ,
145
- index : isize ,
161
+ index : usize ,
146
162
}
147
163
148
164
impl < ' a > Iterator for PyListIterator < ' a > {
149
165
type Item = & ' a PyAny ;
150
166
151
167
#[ inline]
152
168
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 ) ;
169
+ if self . index < self . list . len ( ) {
170
+ #[ cfg( any( Py_LIMITED_API , PyPy ) ) ]
171
+ let item = self . list . get_item ( self . index ) . expect ( "tuple.get failed" ) ;
172
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
173
+ let item = unsafe { self . list . get_item_unchecked ( self . index ) } ;
155
174
self . index += 1 ;
156
175
Some ( item)
157
176
} else {
@@ -164,8 +183,8 @@ impl<'a> Iterator for PyListIterator<'a> {
164
183
let len = self . list . len ( ) ;
165
184
166
185
(
167
- len. saturating_sub ( self . index as usize ) ,
168
- Some ( len. saturating_sub ( self . index as usize ) ) ,
186
+ len. saturating_sub ( self . index ) ,
187
+ Some ( len. saturating_sub ( self . index ) ) ,
169
188
)
170
189
}
171
190
}
@@ -216,10 +235,10 @@ mod tests {
216
235
fn test_new ( ) {
217
236
Python :: with_gil ( |py| {
218
237
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( ) ) ;
238
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
239
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
240
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
241
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
223
242
} ) ;
224
243
}
225
244
@@ -235,19 +254,10 @@ mod tests {
235
254
fn test_get_item ( ) {
236
255
Python :: with_gil ( |py| {
237
256
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 ) ;
257
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
258
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
259
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
260
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
251
261
} ) ;
252
262
}
253
263
@@ -256,9 +266,9 @@ mod tests {
256
266
Python :: with_gil ( |py| {
257
267
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
258
268
let val = 42i32 . to_object ( py) ;
259
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
269
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
260
270
list. set_item ( 0 , val) . unwrap ( ) ;
261
- assert_eq ! ( 42 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
271
+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
262
272
} ) ;
263
273
}
264
274
@@ -286,11 +296,11 @@ mod tests {
286
296
let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
287
297
let val = 42i32 . to_object ( py) ;
288
298
assert_eq ! ( 4 , list. len( ) ) ;
289
- assert_eq ! ( 2 , list. get_item( 0 ) . extract:: <i32 >( ) . unwrap( ) ) ;
299
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
290
300
list. insert ( 0 , val) . unwrap ( ) ;
291
301
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( ) ) ;
302
+ assert_eq ! ( 42 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
303
+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
294
304
} ) ;
295
305
}
296
306
@@ -315,8 +325,8 @@ mod tests {
315
325
Python :: with_gil ( |py| {
316
326
let list = PyList :: new ( py, & [ 2 ] ) ;
317
327
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( ) ) ;
328
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
329
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
320
330
} ) ;
321
331
}
322
332
@@ -393,15 +403,15 @@ mod tests {
393
403
Python :: with_gil ( |py| {
394
404
let v = vec ! [ 7 , 3 , 2 , 5 ] ;
395
405
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( ) ) ;
406
+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
407
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
408
+ assert_eq ! ( 2 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
409
+ assert_eq ! ( 5 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
400
410
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( ) ) ;
411
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
412
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
413
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
414
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
405
415
} ) ;
406
416
}
407
417
@@ -410,15 +420,15 @@ mod tests {
410
420
Python :: with_gil ( |py| {
411
421
let v = vec ! [ 2 , 3 , 5 , 7 ] ;
412
422
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( ) ) ;
423
+ assert_eq ! ( 2 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
424
+ assert_eq ! ( 3 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
425
+ assert_eq ! ( 5 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
426
+ assert_eq ! ( 7 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
417
427
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( ) ) ;
428
+ assert_eq ! ( 7 , list. get_item( 0 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
429
+ assert_eq ! ( 5 , list. get_item( 1 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
430
+ assert_eq ! ( 3 , list. get_item( 2 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
431
+ assert_eq ! ( 2 , list. get_item( 3 ) . unwrap ( ) . extract:: <i32 >( ) . unwrap( ) ) ;
422
432
} ) ;
423
433
}
424
434
@@ -427,8 +437,40 @@ mod tests {
427
437
Python :: with_gil ( |py| {
428
438
let array: PyObject = [ 1 , 2 ] . into_py ( py) ;
429
439
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( ) ) ;
440
+ assert_eq ! ( 1 , list. get_item( 0 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
441
+ assert_eq ! ( 2 , list. get_item( 1 ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ) ;
442
+ } ) ;
443
+ }
444
+
445
+ #[ test]
446
+ fn test_list_get_item_invalid_index ( ) {
447
+ Python :: with_gil ( |py| {
448
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
449
+ let obj = list. get_item ( 5 ) ;
450
+ assert ! ( obj. is_err( ) ) ;
451
+ assert_eq ! (
452
+ obj. unwrap_err( ) . to_string( ) ,
453
+ "IndexError: list index out of range"
454
+ ) ;
455
+ } ) ;
456
+ }
457
+
458
+ #[ test]
459
+ fn test_list_get_item_sanity ( ) {
460
+ Python :: with_gil ( |py| {
461
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
462
+ let obj = list. get_item ( 0 ) ;
463
+ assert_eq ! ( obj. unwrap( ) . extract:: <i32 >( ) . unwrap( ) , 2 ) ;
464
+ } ) ;
465
+ }
466
+
467
+ #[ cfg( not( any( Py_LIMITED_API , PyPy ) ) ) ]
468
+ #[ test]
469
+ fn test_list_get_item_unchecked_sanity ( ) {
470
+ Python :: with_gil ( |py| {
471
+ let list = PyList :: new ( py, & [ 2 , 3 , 5 , 7 ] ) ;
472
+ let obj = unsafe { list. get_item_unchecked ( 0 ) } ;
473
+ assert_eq ! ( obj. extract:: <i32 >( ) . unwrap( ) , 2 ) ;
432
474
} ) ;
433
475
}
434
476
}
0 commit comments