1use std::iter::FusedIterator;
2
3use crate::err::{self, PyResult};
4use crate::ffi::{self, Py_ssize_t};
5use crate::internal_tricks::get_ssize_index;
6use crate::types::{PySequence, PyTuple};
7use crate::{Py, PyAny, PyObject, Python, ToPyObject};
8
9/// Represents a Python `list`.
10#[repr(transparent)]
11pub struct PyList(PyAny);
12
13pyobject_native_type_core!(PyList, pyobject_native_static_type_object!(ffi::PyList_Type), #checkfunction=ffi::PyList_Check);
14
15#[inline]
16#[track_caller]
17pub(crate) fn new_from_iter(
18 py: Python<'_>,
19 elements: &mut dyn ExactSizeIterator<Item = PyObject>,
20) -> Py<PyList> {
21 unsafe {
22 // PyList_New checks for overflow but has a bad error message, so we check ourselves
23 let len: Py_ssize_t = elements
24 .len()
25 .try_into()
26 .expect("out of range integral type conversion attempted on `elements.len()`");
27
28 let ptr = ffi::PyList_New(len);
29
30 // We create the `Py` pointer here for two reasons:
31 // - panics if the ptr is null
32 // - its Drop cleans up the list if user code or the asserts panic.
33 let list: Py<PyList> = Py::from_owned_ptr(py, ptr);
34
35 let mut counter: Py_ssize_t = 0;
36
37 for obj in elements.take(len as usize) {
38 #[cfg(not(Py_LIMITED_API))]
39 ffi::PyList_SET_ITEM(ptr, counter, obj.into_ptr());
40 #[cfg(Py_LIMITED_API)]
41 ffi::PyList_SetItem(ptr, counter, obj.into_ptr());
42 counter += 1;
43 }
44
45 assert!(elements.next().is_none(), "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation.");
46 assert_eq!(len, counter, "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation.");
47
48 list
49 }
50}
51
52impl PyList {
53 /// Constructs a new list with the given elements.
54 ///
55 /// If you want to create a [`PyList`] with elements of different or unknown types, or from an
56 /// iterable that doesn't implement [`ExactSizeIterator`], use [`PyList::append`].
57 ///
58 /// # Examples
59 ///
60 /// ```rust
61 /// use pyo3::prelude::*;
62 /// use pyo3::types::PyList;
63 ///
64 /// # fn main() {
65 /// Python::with_gil(|py| {
66 /// let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
67 /// let list: &PyList = PyList::new(py, elements);
68 /// assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5]");
69 /// });
70 /// # }
71 /// ```
72 ///
73 /// # Panics
74 ///
75 /// This function will panic if `element`'s [`ExactSizeIterator`] implementation is incorrect.
76 /// All standard library structures implement this trait correctly, if they do, so calling this
77 /// function with (for example) [`Vec`]`<T>` or `&[T]` will always succeed.
78 #[track_caller]
79 pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList
80 where
81 T: ToPyObject,
82 U: ExactSizeIterator<Item = T>,
83 {
84 let mut iter = elements.into_iter().map(|e| e.to_object(py));
85 let list = new_from_iter(py, &mut iter);
86 list.into_ref(py)
87 }
88
89 /// Constructs a new empty list.
90 pub fn empty(py: Python<'_>) -> &PyList {
91 unsafe { py.from_owned_ptr::<PyList>(ffi::PyList_New(0)) }
92 }
93
94 /// Returns the length of the list.
95 pub fn len(&self) -> usize {
96 unsafe {
97 #[cfg(not(Py_LIMITED_API))]
98 let size = ffi::PyList_GET_SIZE(self.as_ptr());
99 #[cfg(Py_LIMITED_API)]
100 let size = ffi::PyList_Size(self.as_ptr());
101
102 // non-negative Py_ssize_t should always fit into Rust usize
103 size as usize
104 }
105 }
106
107 /// Checks if the list is empty.
108 pub fn is_empty(&self) -> bool {
109 self.len() == 0
110 }
111
112 /// Returns `self` cast as a `PySequence`.
113 pub fn as_sequence(&self) -> &PySequence {
114 unsafe { self.downcast_unchecked() }
115 }
116
117 /// Gets the list item at the specified index.
118 /// # Example
119 /// ```
120 /// use pyo3::{prelude::*, types::PyList};
121 /// Python::with_gil(|py| {
122 /// let list = PyList::new(py, [2, 3, 5, 7]);
123 /// let obj = list.get_item(0);
124 /// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
125 /// });
126 /// ```
127 pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
128 unsafe {
129 let item = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t);
130 // PyList_GetItem return borrowed ptr; must make owned for safety (see #890).
131 ffi::Py_XINCREF(item);
132 self.py().from_owned_ptr_or_err(item)
133 }
134 }
135
136 /// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
137 ///
138 /// # Safety
139 ///
140 /// Caller must verify that the index is within the bounds of the list.
141 #[cfg(not(Py_LIMITED_API))]
142 pub unsafe fn get_item_unchecked(&self, index: usize) -> &PyAny {
143 let item = ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t);
144 // PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890).
145 ffi::Py_XINCREF(item);
146 self.py().from_owned_ptr(item)
147 }
148
149 /// Takes the slice `self[low:high]` and returns it as a new list.
150 ///
151 /// Indices must be nonnegative, and out-of-range indices are clipped to
152 /// `self.len()`.
153 pub fn get_slice(&self, low: usize, high: usize) -> &PyList {
154 unsafe {
155 self.py().from_owned_ptr(ffi::PyList_GetSlice(
156 self.as_ptr(),
157 get_ssize_index(low),
158 get_ssize_index(high),
159 ))
160 }
161 }
162
163 /// Sets the item at the specified index.
164 ///
165 /// Raises `IndexError` if the index is out of range.
166 pub fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
167 where
168 I: ToPyObject,
169 {
170 fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
171 err::error_on_minusone(list.py(), unsafe {
172 ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
173 })
174 }
175
176 inner(self, index, item.to_object(self.py()))
177 }
178
179 /// Deletes the `index`th element of self.
180 ///
181 /// This is equivalent to the Python statement `del self[i]`.
182 #[inline]
183 pub fn del_item(&self, index: usize) -> PyResult<()> {
184 self.as_sequence().del_item(index)
185 }
186
187 /// Assigns the sequence `seq` to the slice of `self` from `low` to `high`.
188 ///
189 /// This is equivalent to the Python statement `self[low:high] = v`.
190 #[inline]
191 pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> {
192 err::error_on_minusone(self.py(), unsafe {
193 ffi::PyList_SetSlice(
194 self.as_ptr(),
195 get_ssize_index(low),
196 get_ssize_index(high),
197 seq.as_ptr(),
198 )
199 })
200 }
201
202 /// Deletes the slice from `low` to `high` from `self`.
203 ///
204 /// This is equivalent to the Python statement `del self[low:high]`.
205 #[inline]
206 pub fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
207 self.as_sequence().del_slice(low, high)
208 }
209
210 /// Appends an item to the list.
211 pub fn append<I>(&self, item: I) -> PyResult<()>
212 where
213 I: ToPyObject,
214 {
215 fn inner(list: &PyList, item: PyObject) -> PyResult<()> {
216 err::error_on_minusone(list.py(), unsafe {
217 ffi::PyList_Append(list.as_ptr(), item.as_ptr())
218 })
219 }
220
221 inner(self, item.to_object(self.py()))
222 }
223
224 /// Inserts an item at the specified index.
225 ///
226 /// If `index >= self.len()`, inserts at the end.
227 pub fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
228 where
229 I: ToPyObject,
230 {
231 fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
232 err::error_on_minusone(list.py(), unsafe {
233 ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
234 })
235 }
236
237 inner(self, index, item.to_object(self.py()))
238 }
239
240 /// Determines if self contains `value`.
241 ///
242 /// This is equivalent to the Python expression `value in self`.
243 #[inline]
244 pub fn contains<V>(&self, value: V) -> PyResult<bool>
245 where
246 V: ToPyObject,
247 {
248 self.as_sequence().contains(value)
249 }
250
251 /// Returns the first index `i` for which `self[i] == value`.
252 ///
253 /// This is equivalent to the Python expression `self.index(value)`.
254 #[inline]
255 pub fn index<V>(&self, value: V) -> PyResult<usize>
256 where
257 V: ToPyObject,
258 {
259 self.as_sequence().index(value)
260 }
261
262 /// Returns an iterator over this list's items.
263 pub fn iter(&self) -> PyListIterator<'_> {
264 PyListIterator {
265 list: self,
266 index: 0,
267 length: self.len(),
268 }
269 }
270
271 /// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
272 pub fn sort(&self) -> PyResult<()> {
273 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
274 }
275
276 /// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
277 pub fn reverse(&self) -> PyResult<()> {
278 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
279 }
280
281 /// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.
282 ///
283 /// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`.
284 pub fn to_tuple(&self) -> &PyTuple {
285 unsafe { self.py().from_owned_ptr(ffi::PyList_AsTuple(self.as_ptr())) }
286 }
287}
288
289index_impls!(PyList, "list", PyList::len, PyList::get_slice);
290
291/// Used by `PyList::iter()`.
292pub struct PyListIterator<'a> {
293 list: &'a PyList,
294 index: usize,
295 length: usize,
296}
297
298impl<'a> PyListIterator<'a> {
299 unsafe fn get_item(&self, index: usize) -> &'a PyAny {
300 #[cfg(any(Py_LIMITED_API, PyPy))]
301 let item = self.list.get_item(index).expect("list.get failed");
302 #[cfg(not(any(Py_LIMITED_API, PyPy)))]
303 let item: &PyAny = self.list.get_item_unchecked(index);
304 item
305 }
306}
307
308impl<'a> Iterator for PyListIterator<'a> {
309 type Item = &'a PyAny;
310
311 #[inline]
312 fn next(&mut self) -> Option<Self::Item> {
313 let length: usize = self.length.min(self.list.len());
314
315 if self.index < length {
316 let item: &PyAny = unsafe { self.get_item(self.index) };
317 self.index += 1;
318 Some(item)
319 } else {
320 None
321 }
322 }
323
324 #[inline]
325 fn size_hint(&self) -> (usize, Option<usize>) {
326 let len: usize = self.len();
327 (len, Some(len))
328 }
329}
330
331impl<'a> DoubleEndedIterator for PyListIterator<'a> {
332 #[inline]
333 fn next_back(&mut self) -> Option<Self::Item> {
334 let length: usize = self.length.min(self.list.len());
335
336 if self.index < length {
337 let item: &PyAny = unsafe { self.get_item(index:length - 1) };
338 self.length = length - 1;
339 Some(item)
340 } else {
341 None
342 }
343 }
344}
345
346impl<'a> ExactSizeIterator for PyListIterator<'a> {
347 fn len(&self) -> usize {
348 self.length.saturating_sub(self.index)
349 }
350}
351
352impl FusedIterator for PyListIterator<'_> {}
353
354impl<'a> IntoIterator for &'a PyList {
355 type Item = &'a PyAny;
356 type IntoIter = PyListIterator<'a>;
357
358 fn into_iter(self) -> Self::IntoIter {
359 self.iter()
360 }
361}
362
363#[cfg(test)]
364mod tests {
365 use crate::types::{PyList, PyTuple};
366 use crate::Python;
367 use crate::{IntoPy, PyObject, ToPyObject};
368
369 #[test]
370 fn test_new() {
371 Python::with_gil(|py| {
372 let list = PyList::new(py, [2, 3, 5, 7]);
373 assert_eq!(2, list[0].extract::<i32>().unwrap());
374 assert_eq!(3, list[1].extract::<i32>().unwrap());
375 assert_eq!(5, list[2].extract::<i32>().unwrap());
376 assert_eq!(7, list[3].extract::<i32>().unwrap());
377 });
378 }
379
380 #[test]
381 fn test_len() {
382 Python::with_gil(|py| {
383 let list = PyList::new(py, [1, 2, 3, 4]);
384 assert_eq!(4, list.len());
385 });
386 }
387
388 #[test]
389 fn test_get_item() {
390 Python::with_gil(|py| {
391 let list = PyList::new(py, [2, 3, 5, 7]);
392 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
393 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
394 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
395 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
396 });
397 }
398
399 #[test]
400 fn test_get_slice() {
401 Python::with_gil(|py| {
402 let list = PyList::new(py, [2, 3, 5, 7]);
403 let slice = list.get_slice(1, 3);
404 assert_eq!(2, slice.len());
405 let slice = list.get_slice(1, 7);
406 assert_eq!(3, slice.len());
407 });
408 }
409
410 #[test]
411 fn test_set_item() {
412 Python::with_gil(|py| {
413 let list = PyList::new(py, [2, 3, 5, 7]);
414 let val = 42i32.to_object(py);
415 let val2 = 42i32.to_object(py);
416 assert_eq!(2, list[0].extract::<i32>().unwrap());
417 list.set_item(0, val).unwrap();
418 assert_eq!(42, list[0].extract::<i32>().unwrap());
419 assert!(list.set_item(10, val2).is_err());
420 });
421 }
422
423 #[test]
424 fn test_set_item_refcnt() {
425 Python::with_gil(|py| {
426 let obj = py.eval("object()", None, None).unwrap();
427 let cnt;
428 {
429 let _pool = unsafe { crate::GILPool::new() };
430 let v = vec![2];
431 let ob = v.to_object(py);
432 let list: &PyList = ob.downcast(py).unwrap();
433 cnt = obj.get_refcnt();
434 list.set_item(0, obj).unwrap();
435 }
436
437 assert_eq!(cnt, obj.get_refcnt());
438 });
439 }
440
441 #[test]
442 fn test_insert() {
443 Python::with_gil(|py| {
444 let list = PyList::new(py, [2, 3, 5, 7]);
445 let val = 42i32.to_object(py);
446 let val2 = 43i32.to_object(py);
447 assert_eq!(4, list.len());
448 assert_eq!(2, list[0].extract::<i32>().unwrap());
449 list.insert(0, val).unwrap();
450 list.insert(1000, val2).unwrap();
451 assert_eq!(6, list.len());
452 assert_eq!(42, list[0].extract::<i32>().unwrap());
453 assert_eq!(2, list[1].extract::<i32>().unwrap());
454 assert_eq!(43, list[5].extract::<i32>().unwrap());
455 });
456 }
457
458 #[test]
459 fn test_insert_refcnt() {
460 Python::with_gil(|py| {
461 let cnt;
462 let obj = py.eval("object()", None, None).unwrap();
463 {
464 let _pool = unsafe { crate::GILPool::new() };
465 let list = PyList::empty(py);
466 cnt = obj.get_refcnt();
467 list.insert(0, obj).unwrap();
468 }
469
470 assert_eq!(cnt, obj.get_refcnt());
471 });
472 }
473
474 #[test]
475 fn test_append() {
476 Python::with_gil(|py| {
477 let list = PyList::new(py, [2]);
478 list.append(3).unwrap();
479 assert_eq!(2, list[0].extract::<i32>().unwrap());
480 assert_eq!(3, list[1].extract::<i32>().unwrap());
481 });
482 }
483
484 #[test]
485 fn test_append_refcnt() {
486 Python::with_gil(|py| {
487 let cnt;
488 let obj = py.eval("object()", None, None).unwrap();
489 {
490 let _pool = unsafe { crate::GILPool::new() };
491 let list = PyList::empty(py);
492 cnt = obj.get_refcnt();
493 list.append(obj).unwrap();
494 }
495 assert_eq!(cnt, obj.get_refcnt());
496 });
497 }
498
499 #[test]
500 fn test_iter() {
501 Python::with_gil(|py| {
502 let v = vec![2, 3, 5, 7];
503 let list = PyList::new(py, &v);
504 let mut idx = 0;
505 for el in list {
506 assert_eq!(v[idx], el.extract::<i32>().unwrap());
507 idx += 1;
508 }
509 assert_eq!(idx, v.len());
510 });
511 }
512
513 #[test]
514 fn test_iter_size_hint() {
515 Python::with_gil(|py| {
516 let v = vec![2, 3, 5, 7];
517 let ob = v.to_object(py);
518 let list: &PyList = ob.downcast(py).unwrap();
519
520 let mut iter = list.iter();
521 assert_eq!(iter.size_hint(), (v.len(), Some(v.len())));
522 iter.next();
523 assert_eq!(iter.size_hint(), (v.len() - 1, Some(v.len() - 1)));
524
525 // Exhaust iterator.
526 for _ in &mut iter {}
527
528 assert_eq!(iter.size_hint(), (0, Some(0)));
529 });
530 }
531
532 #[test]
533 fn test_iter_rev() {
534 Python::with_gil(|py| {
535 let v = vec![2, 3, 5, 7];
536 let ob = v.to_object(py);
537 let list: &PyList = ob.downcast(py).unwrap();
538
539 let mut iter = list.iter().rev();
540
541 assert_eq!(iter.size_hint(), (4, Some(4)));
542
543 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 7);
544 assert_eq!(iter.size_hint(), (3, Some(3)));
545
546 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 5);
547 assert_eq!(iter.size_hint(), (2, Some(2)));
548
549 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
550 assert_eq!(iter.size_hint(), (1, Some(1)));
551
552 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 2);
553 assert_eq!(iter.size_hint(), (0, Some(0)));
554
555 assert!(iter.next().is_none());
556 assert!(iter.next().is_none());
557 });
558 }
559
560 #[test]
561 fn test_into_iter() {
562 Python::with_gil(|py| {
563 let list = PyList::new(py, [1, 2, 3, 4]);
564 for (i, item) in list.iter().enumerate() {
565 assert_eq!((i + 1) as i32, item.extract::<i32>().unwrap());
566 }
567 });
568 }
569
570 #[test]
571 fn test_extract() {
572 Python::with_gil(|py| {
573 let v = vec![2, 3, 5, 7];
574 let list = PyList::new(py, &v);
575 let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
576 assert_eq!(v, v2);
577 });
578 }
579
580 #[test]
581 fn test_sort() {
582 Python::with_gil(|py| {
583 let v = vec![7, 3, 2, 5];
584 let list = PyList::new(py, &v);
585 assert_eq!(7, list[0].extract::<i32>().unwrap());
586 assert_eq!(3, list[1].extract::<i32>().unwrap());
587 assert_eq!(2, list[2].extract::<i32>().unwrap());
588 assert_eq!(5, list[3].extract::<i32>().unwrap());
589 list.sort().unwrap();
590 assert_eq!(2, list[0].extract::<i32>().unwrap());
591 assert_eq!(3, list[1].extract::<i32>().unwrap());
592 assert_eq!(5, list[2].extract::<i32>().unwrap());
593 assert_eq!(7, list[3].extract::<i32>().unwrap());
594 });
595 }
596
597 #[test]
598 fn test_reverse() {
599 Python::with_gil(|py| {
600 let v = vec![2, 3, 5, 7];
601 let list = PyList::new(py, &v);
602 assert_eq!(2, list[0].extract::<i32>().unwrap());
603 assert_eq!(3, list[1].extract::<i32>().unwrap());
604 assert_eq!(5, list[2].extract::<i32>().unwrap());
605 assert_eq!(7, list[3].extract::<i32>().unwrap());
606 list.reverse().unwrap();
607 assert_eq!(7, list[0].extract::<i32>().unwrap());
608 assert_eq!(5, list[1].extract::<i32>().unwrap());
609 assert_eq!(3, list[2].extract::<i32>().unwrap());
610 assert_eq!(2, list[3].extract::<i32>().unwrap());
611 });
612 }
613
614 #[test]
615 fn test_array_into_py() {
616 Python::with_gil(|py| {
617 let array: PyObject = [1, 2].into_py(py);
618 let list: &PyList = array.downcast(py).unwrap();
619 assert_eq!(1, list[0].extract::<i32>().unwrap());
620 assert_eq!(2, list[1].extract::<i32>().unwrap());
621 });
622 }
623
624 #[test]
625 fn test_list_get_item_invalid_index() {
626 Python::with_gil(|py| {
627 let list = PyList::new(py, [2, 3, 5, 7]);
628 let obj = list.get_item(5);
629 assert!(obj.is_err());
630 assert_eq!(
631 obj.unwrap_err().to_string(),
632 "IndexError: list index out of range"
633 );
634 });
635 }
636
637 #[test]
638 fn test_list_get_item_sanity() {
639 Python::with_gil(|py| {
640 let list = PyList::new(py, [2, 3, 5, 7]);
641 let obj = list.get_item(0);
642 assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
643 });
644 }
645
646 #[cfg(not(any(Py_LIMITED_API, PyPy)))]
647 #[test]
648 fn test_list_get_item_unchecked_sanity() {
649 Python::with_gil(|py| {
650 let list = PyList::new(py, [2, 3, 5, 7]);
651 let obj = unsafe { list.get_item_unchecked(0) };
652 assert_eq!(obj.extract::<i32>().unwrap(), 2);
653 });
654 }
655
656 #[test]
657 fn test_list_index_trait() {
658 Python::with_gil(|py| {
659 let list = PyList::new(py, [2, 3, 5]);
660 assert_eq!(2, list[0].extract::<i32>().unwrap());
661 assert_eq!(3, list[1].extract::<i32>().unwrap());
662 assert_eq!(5, list[2].extract::<i32>().unwrap());
663 });
664 }
665
666 #[test]
667 #[should_panic]
668 fn test_list_index_trait_panic() {
669 Python::with_gil(|py| {
670 let list = PyList::new(py, [2, 3, 5]);
671 let _ = &list[7];
672 });
673 }
674
675 #[test]
676 fn test_list_index_trait_ranges() {
677 Python::with_gil(|py| {
678 let list = PyList::new(py, [2, 3, 5]);
679 assert_eq!(vec![3, 5], list[1..3].extract::<Vec<i32>>().unwrap());
680 assert_eq!(Vec::<i32>::new(), list[3..3].extract::<Vec<i32>>().unwrap());
681 assert_eq!(vec![3, 5], list[1..].extract::<Vec<i32>>().unwrap());
682 assert_eq!(Vec::<i32>::new(), list[3..].extract::<Vec<i32>>().unwrap());
683 assert_eq!(vec![2, 3, 5], list[..].extract::<Vec<i32>>().unwrap());
684 assert_eq!(vec![3, 5], list[1..=2].extract::<Vec<i32>>().unwrap());
685 assert_eq!(vec![2, 3], list[..2].extract::<Vec<i32>>().unwrap());
686 assert_eq!(vec![2, 3], list[..=1].extract::<Vec<i32>>().unwrap());
687 })
688 }
689
690 #[test]
691 #[should_panic = "range start index 5 out of range for list of length 3"]
692 fn test_list_index_trait_range_panic_start() {
693 Python::with_gil(|py| {
694 let list = PyList::new(py, [2, 3, 5]);
695 list[5..10].extract::<Vec<i32>>().unwrap();
696 })
697 }
698
699 #[test]
700 #[should_panic = "range end index 10 out of range for list of length 3"]
701 fn test_list_index_trait_range_panic_end() {
702 Python::with_gil(|py| {
703 let list = PyList::new(py, [2, 3, 5]);
704 list[1..10].extract::<Vec<i32>>().unwrap();
705 })
706 }
707
708 #[test]
709 #[should_panic = "slice index starts at 2 but ends at 1"]
710 fn test_list_index_trait_range_panic_wrong_order() {
711 Python::with_gil(|py| {
712 let list = PyList::new(py, [2, 3, 5]);
713 #[allow(clippy::reversed_empty_ranges)]
714 list[2..1].extract::<Vec<i32>>().unwrap();
715 })
716 }
717
718 #[test]
719 #[should_panic = "range start index 8 out of range for list of length 3"]
720 fn test_list_index_trait_range_from_panic() {
721 Python::with_gil(|py| {
722 let list = PyList::new(py, [2, 3, 5]);
723 list[8..].extract::<Vec<i32>>().unwrap();
724 })
725 }
726
727 #[test]
728 fn test_list_del_item() {
729 Python::with_gil(|py| {
730 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]);
731 assert!(list.del_item(10).is_err());
732 assert_eq!(1, list[0].extract::<i32>().unwrap());
733 assert!(list.del_item(0).is_ok());
734 assert_eq!(1, list[0].extract::<i32>().unwrap());
735 assert!(list.del_item(0).is_ok());
736 assert_eq!(2, list[0].extract::<i32>().unwrap());
737 assert!(list.del_item(0).is_ok());
738 assert_eq!(3, list[0].extract::<i32>().unwrap());
739 assert!(list.del_item(0).is_ok());
740 assert_eq!(5, list[0].extract::<i32>().unwrap());
741 assert!(list.del_item(0).is_ok());
742 assert_eq!(8, list[0].extract::<i32>().unwrap());
743 assert!(list.del_item(0).is_ok());
744 assert_eq!(0, list.len());
745 assert!(list.del_item(0).is_err());
746 });
747 }
748
749 #[test]
750 fn test_list_set_slice() {
751 Python::with_gil(|py| {
752 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]);
753 let ins = PyList::new(py, [7, 4]);
754 list.set_slice(1, 4, ins).unwrap();
755 assert_eq!([1, 7, 4, 5, 8], list.extract::<[i32; 5]>().unwrap());
756 list.set_slice(3, 100, PyList::empty(py)).unwrap();
757 assert_eq!([1, 7, 4], list.extract::<[i32; 3]>().unwrap());
758 });
759 }
760
761 #[test]
762 fn test_list_del_slice() {
763 Python::with_gil(|py| {
764 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]);
765 list.del_slice(1, 4).unwrap();
766 assert_eq!([1, 5, 8], list.extract::<[i32; 3]>().unwrap());
767 list.del_slice(1, 100).unwrap();
768 assert_eq!([1], list.extract::<[i32; 1]>().unwrap());
769 });
770 }
771
772 #[test]
773 fn test_list_contains() {
774 Python::with_gil(|py| {
775 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]);
776 assert_eq!(6, list.len());
777
778 let bad_needle = 7i32.to_object(py);
779 assert!(!list.contains(&bad_needle).unwrap());
780
781 let good_needle = 8i32.to_object(py);
782 assert!(list.contains(&good_needle).unwrap());
783
784 let type_coerced_needle = 8f32.to_object(py);
785 assert!(list.contains(&type_coerced_needle).unwrap());
786 });
787 }
788
789 #[test]
790 fn test_list_index() {
791 Python::with_gil(|py| {
792 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]);
793 assert_eq!(0, list.index(1i32).unwrap());
794 assert_eq!(2, list.index(2i32).unwrap());
795 assert_eq!(3, list.index(3i32).unwrap());
796 assert_eq!(4, list.index(5i32).unwrap());
797 assert_eq!(5, list.index(8i32).unwrap());
798 assert!(list.index(42i32).is_err());
799 });
800 }
801
802 use std::ops::Range;
803
804 // An iterator that lies about its `ExactSizeIterator` implementation.
805 // See https://github.com/PyO3/pyo3/issues/2118
806 struct FaultyIter(Range<usize>, usize);
807
808 impl Iterator for FaultyIter {
809 type Item = usize;
810
811 fn next(&mut self) -> Option<Self::Item> {
812 self.0.next()
813 }
814 }
815
816 impl ExactSizeIterator for FaultyIter {
817 fn len(&self) -> usize {
818 self.1
819 }
820 }
821
822 #[test]
823 #[should_panic(
824 expected = "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation."
825 )]
826 fn too_long_iterator() {
827 Python::with_gil(|py| {
828 let iter = FaultyIter(0..usize::MAX, 73);
829 let _list = PyList::new(py, iter);
830 })
831 }
832
833 #[test]
834 #[should_panic(
835 expected = "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation."
836 )]
837 fn too_short_iterator() {
838 Python::with_gil(|py| {
839 let iter = FaultyIter(0..35, 73);
840 let _list = PyList::new(py, iter);
841 })
842 }
843
844 #[test]
845 #[should_panic(
846 expected = "out of range integral type conversion attempted on `elements.len()`"
847 )]
848 fn overflowing_size() {
849 Python::with_gil(|py| {
850 let iter = FaultyIter(0..0, usize::MAX);
851
852 let _list = PyList::new(py, iter);
853 })
854 }
855
856 #[cfg(feature = "macros")]
857 #[test]
858 fn bad_clone_mem_leaks() {
859 use crate::{Py, PyAny};
860 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
861 static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0);
862
863 #[crate::pyclass]
864 #[pyo3(crate = "crate")]
865 struct Bad(usize);
866
867 impl Clone for Bad {
868 fn clone(&self) -> Self {
869 // This panic should not lead to a memory leak
870 assert_ne!(self.0, 42);
871 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
872
873 Bad(self.0)
874 }
875 }
876
877 impl Drop for Bad {
878 fn drop(&mut self) {
879 NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst);
880 }
881 }
882
883 impl ToPyObject for Bad {
884 fn to_object(&self, py: Python<'_>) -> Py<PyAny> {
885 self.to_owned().into_py(py)
886 }
887 }
888
889 struct FaultyIter(Range<usize>, usize);
890
891 impl Iterator for FaultyIter {
892 type Item = Bad;
893
894 fn next(&mut self) -> Option<Self::Item> {
895 self.0.next().map(|i| {
896 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
897 Bad(i)
898 })
899 }
900 }
901
902 impl ExactSizeIterator for FaultyIter {
903 fn len(&self) -> usize {
904 self.1
905 }
906 }
907
908 Python::with_gil(|py| {
909 std::panic::catch_unwind(|| {
910 let iter = FaultyIter(0..50, 50);
911 let _list = PyList::new(py, iter);
912 })
913 .unwrap_err();
914 });
915
916 assert_eq!(
917 NEEDS_DESTRUCTING_COUNT.load(SeqCst),
918 0,
919 "Some destructors did not run"
920 );
921 }
922
923 #[test]
924 fn test_list_to_tuple() {
925 Python::with_gil(|py| {
926 let list = PyList::new(py, vec![1, 2, 3]);
927 let tuple = list.to_tuple();
928 let tuple_expected = PyTuple::new(py, vec![1, 2, 3]);
929 assert!(tuple.eq(tuple_expected).unwrap());
930 })
931 }
932}
933