1use std::iter::FusedIterator;
2
3use crate::err::{self, PyResult};
4use crate::ffi::{self, Py_ssize_t};
5use crate::ffi_ptr_ext::FfiPtrExt;
6use crate::internal_tricks::get_ssize_index;
7use crate::types::{PySequence, PyTuple};
8#[cfg(feature = "gil-refs")]
9use crate::PyNativeType;
10use crate::{Bound, PyAny, PyObject, Python, ToPyObject};
11
12use crate::types::any::PyAnyMethods;
13use crate::types::sequence::PySequenceMethods;
14
15#[repr(transparent)]
23pub struct PyList(PyAny);
24
25pyobject_native_type_core!(PyList, pyobject_native_static_type_object!(ffi::PyList_Type), #checkfunction=ffi::PyList_Check);
26
27#[inline]
28#[track_caller]
29pub(crate) fn new_from_iter<'py>(
30 py: Python<'py>,
31 elements: &mut dyn ExactSizeIterator<Item = PyObject>,
32) -> Bound<'py, PyList> {
33 unsafe {
34 let len: Py_ssize_t = elements
36 .len()
37 .try_into()
38 .expect("out of range integral type conversion attempted on `elements.len()`");
39
40 let ptr = ffi::PyList_New(len);
41
42 let list = ptr.assume_owned(py).downcast_into_unchecked();
46
47 let mut counter: Py_ssize_t = 0;
48
49 for obj in elements.take(len as usize) {
50 #[cfg(not(Py_LIMITED_API))]
51 ffi::PyList_SET_ITEM(ptr, counter, obj.into_ptr());
52 #[cfg(Py_LIMITED_API)]
53 ffi::PyList_SetItem(ptr, counter, obj.into_ptr());
54 counter += 1;
55 }
56
57 assert!(elements.next().is_none(), "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation.");
58 assert_eq!(len, counter, "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation.");
59
60 list
61 }
62}
63
64impl PyList {
65 #[track_caller]
91 pub fn new_bound<T, U>(
92 py: Python<'_>,
93 elements: impl IntoIterator<Item = T, IntoIter = U>,
94 ) -> Bound<'_, PyList>
95 where
96 T: ToPyObject,
97 U: ExactSizeIterator<Item = T>,
98 {
99 let mut iter = elements.into_iter().map(|e| e.to_object(py));
100 new_from_iter(py, &mut iter)
101 }
102
103 pub fn empty_bound(py: Python<'_>) -> Bound<'_, PyList> {
105 unsafe {
106 ffi::PyList_New(0)
107 .assume_owned(py)
108 .downcast_into_unchecked()
109 }
110 }
111}
112
113#[cfg(feature = "gil-refs")]
114impl PyList {
115 #[inline]
117 #[track_caller]
118 #[deprecated(
119 since = "0.21.0",
120 note = "`PyList::new` will be replaced by `PyList::new_bound` in a future PyO3 version"
121 )]
122 pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList
123 where
124 T: ToPyObject,
125 U: ExactSizeIterator<Item = T>,
126 {
127 Self::new_bound(py, elements).into_gil_ref()
128 }
129
130 #[inline]
132 #[deprecated(
133 since = "0.21.0",
134 note = "`PyList::empty` will be replaced by `PyList::empty_bound` in a future PyO3 version"
135 )]
136 pub fn empty(py: Python<'_>) -> &PyList {
137 Self::empty_bound(py).into_gil_ref()
138 }
139
140 pub fn len(&self) -> usize {
142 self.as_borrowed().len()
143 }
144
145 pub fn is_empty(&self) -> bool {
147 self.as_borrowed().is_empty()
148 }
149
150 pub fn as_sequence(&self) -> &PySequence {
152 unsafe { self.downcast_unchecked() }
153 }
154
155 pub fn get_item(&self, index: usize) -> PyResult<&PyAny> {
166 self.as_borrowed().get_item(index).map(Bound::into_gil_ref)
167 }
168
169 #[cfg(not(Py_LIMITED_API))]
175 pub unsafe fn get_item_unchecked(&self, index: usize) -> &PyAny {
176 self.as_borrowed().get_item_unchecked(index).into_gil_ref()
177 }
178
179 pub fn get_slice(&self, low: usize, high: usize) -> &PyList {
184 self.as_borrowed().get_slice(low, high).into_gil_ref()
185 }
186
187 pub fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
191 where
192 I: ToPyObject,
193 {
194 self.as_borrowed().set_item(index, item)
195 }
196
197 #[inline]
201 pub fn del_item(&self, index: usize) -> PyResult<()> {
202 self.as_borrowed().del_item(index)
203 }
204
205 #[inline]
209 pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> {
210 self.as_borrowed().set_slice(low, high, &seq.as_borrowed())
211 }
212
213 #[inline]
217 pub fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
218 self.as_borrowed().del_slice(low, high)
219 }
220
221 pub fn append<I>(&self, item: I) -> PyResult<()>
223 where
224 I: ToPyObject,
225 {
226 self.as_borrowed().append(item)
227 }
228
229 pub fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
233 where
234 I: ToPyObject,
235 {
236 self.as_borrowed().insert(index, item)
237 }
238
239 #[inline]
243 pub fn contains<V>(&self, value: V) -> PyResult<bool>
244 where
245 V: ToPyObject,
246 {
247 self.as_borrowed().contains(value)
248 }
249
250 #[inline]
254 pub fn index<V>(&self, value: V) -> PyResult<usize>
255 where
256 V: ToPyObject,
257 {
258 self.as_borrowed().index(value)
259 }
260
261 pub fn iter(&self) -> PyListIterator<'_> {
263 PyListIterator(self.as_borrowed().iter())
264 }
265
266 pub fn sort(&self) -> PyResult<()> {
268 self.as_borrowed().sort()
269 }
270
271 pub fn reverse(&self) -> PyResult<()> {
273 self.as_borrowed().reverse()
274 }
275
276 pub fn to_tuple(&self) -> &PyTuple {
280 self.as_borrowed().to_tuple().into_gil_ref()
281 }
282}
283
284#[cfg(feature = "gil-refs")]
285index_impls!(PyList, "list", PyList::len, PyList::get_slice);
286
287#[doc(alias = "PyList")]
293pub trait PyListMethods<'py>: crate::sealed::Sealed {
294 fn len(&self) -> usize;
296
297 fn is_empty(&self) -> bool;
299
300 fn as_sequence(&self) -> &Bound<'py, PySequence>;
302
303 fn into_sequence(self) -> Bound<'py, PySequence>;
305
306 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
317
318 #[cfg(not(Py_LIMITED_API))]
324 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny>;
325
326 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList>;
331
332 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
336 where
337 I: ToPyObject;
338
339 fn del_item(&self, index: usize) -> PyResult<()>;
343
344 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()>;
348
349 fn del_slice(&self, low: usize, high: usize) -> PyResult<()>;
353
354 fn append<I>(&self, item: I) -> PyResult<()>
356 where
357 I: ToPyObject;
358
359 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
363 where
364 I: ToPyObject;
365
366 fn contains<V>(&self, value: V) -> PyResult<bool>
370 where
371 V: ToPyObject;
372
373 fn index<V>(&self, value: V) -> PyResult<usize>
377 where
378 V: ToPyObject;
379
380 fn iter(&self) -> BoundListIterator<'py>;
382
383 fn sort(&self) -> PyResult<()>;
385
386 fn reverse(&self) -> PyResult<()>;
388
389 fn to_tuple(&self) -> Bound<'py, PyTuple>;
393}
394
395impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
396 fn len(&self) -> usize {
398 unsafe {
399 #[cfg(not(Py_LIMITED_API))]
400 let size = ffi::PyList_GET_SIZE(self.as_ptr());
401 #[cfg(Py_LIMITED_API)]
402 let size = ffi::PyList_Size(self.as_ptr());
403
404 size as usize
406 }
407 }
408
409 fn is_empty(&self) -> bool {
411 self.len() == 0
412 }
413
414 fn as_sequence(&self) -> &Bound<'py, PySequence> {
416 unsafe { self.downcast_unchecked() }
417 }
418
419 fn into_sequence(self) -> Bound<'py, PySequence> {
421 unsafe { self.into_any().downcast_into_unchecked() }
422 }
423
424 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
435 unsafe {
436 ffi::compat::PyList_GetItemRef(self.as_ptr(), index as Py_ssize_t)
437 .assume_owned_or_err(self.py())
438 }
439 }
440
441 #[cfg(not(Py_LIMITED_API))]
447 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny> {
448 ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t)
450 .assume_borrowed(self.py())
451 .to_owned()
452 }
453
454 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList> {
459 unsafe {
460 ffi::PyList_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
461 .assume_owned(self.py())
462 .downcast_into_unchecked()
463 }
464 }
465
466 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
470 where
471 I: ToPyObject,
472 {
473 fn inner(list: &Bound<'_, PyList>, index: usize, item: Bound<'_, PyAny>) -> PyResult<()> {
474 err::error_on_minusone(list.py(), unsafe {
475 ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
476 })
477 }
478
479 let py = self.py();
480 inner(self, index, item.to_object(py).into_bound(py))
481 }
482
483 #[inline]
487 fn del_item(&self, index: usize) -> PyResult<()> {
488 self.as_sequence().del_item(index)
489 }
490
491 #[inline]
495 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()> {
496 err::error_on_minusone(self.py(), unsafe {
497 ffi::PyList_SetSlice(
498 self.as_ptr(),
499 get_ssize_index(low),
500 get_ssize_index(high),
501 seq.as_ptr(),
502 )
503 })
504 }
505
506 #[inline]
510 fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
511 self.as_sequence().del_slice(low, high)
512 }
513
514 fn append<I>(&self, item: I) -> PyResult<()>
516 where
517 I: ToPyObject,
518 {
519 fn inner(list: &Bound<'_, PyList>, item: Bound<'_, PyAny>) -> PyResult<()> {
520 err::error_on_minusone(list.py(), unsafe {
521 ffi::PyList_Append(list.as_ptr(), item.as_ptr())
522 })
523 }
524
525 let py = self.py();
526 inner(self, item.to_object(py).into_bound(py))
527 }
528
529 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
533 where
534 I: ToPyObject,
535 {
536 fn inner(list: &Bound<'_, PyList>, index: usize, item: Bound<'_, PyAny>) -> PyResult<()> {
537 err::error_on_minusone(list.py(), unsafe {
538 ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
539 })
540 }
541
542 let py = self.py();
543 inner(self, index, item.to_object(py).into_bound(py))
544 }
545
546 #[inline]
550 fn contains<V>(&self, value: V) -> PyResult<bool>
551 where
552 V: ToPyObject,
553 {
554 self.as_sequence().contains(value)
555 }
556
557 #[inline]
561 fn index<V>(&self, value: V) -> PyResult<usize>
562 where
563 V: ToPyObject,
564 {
565 self.as_sequence().index(value)
566 }
567
568 fn iter(&self) -> BoundListIterator<'py> {
570 BoundListIterator::new(self.clone())
571 }
572
573 fn sort(&self) -> PyResult<()> {
575 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
576 }
577
578 fn reverse(&self) -> PyResult<()> {
580 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
581 }
582
583 fn to_tuple(&self) -> Bound<'py, PyTuple> {
587 unsafe {
588 ffi::PyList_AsTuple(self.as_ptr())
589 .assume_owned(self.py())
590 .downcast_into_unchecked()
591 }
592 }
593}
594
595#[cfg(feature = "gil-refs")]
597pub struct PyListIterator<'a>(BoundListIterator<'a>);
598
599#[cfg(feature = "gil-refs")]
600impl<'a> Iterator for PyListIterator<'a> {
601 type Item = &'a PyAny;
602
603 #[inline]
604 fn next(&mut self) -> Option<Self::Item> {
605 self.0.next().map(Bound::into_gil_ref)
606 }
607
608 #[inline]
609 fn size_hint(&self) -> (usize, Option<usize>) {
610 self.0.size_hint()
611 }
612}
613
614#[cfg(feature = "gil-refs")]
615impl<'a> DoubleEndedIterator for PyListIterator<'a> {
616 #[inline]
617 fn next_back(&mut self) -> Option<Self::Item> {
618 self.0.next_back().map(Bound::into_gil_ref)
619 }
620}
621
622#[cfg(feature = "gil-refs")]
623impl<'a> ExactSizeIterator for PyListIterator<'a> {
624 fn len(&self) -> usize {
625 self.0.len()
626 }
627}
628
629#[cfg(feature = "gil-refs")]
630impl FusedIterator for PyListIterator<'_> {}
631
632#[cfg(feature = "gil-refs")]
633impl<'a> IntoIterator for &'a PyList {
634 type Item = &'a PyAny;
635 type IntoIter = PyListIterator<'a>;
636
637 fn into_iter(self) -> Self::IntoIter {
638 self.iter()
639 }
640}
641
642pub struct BoundListIterator<'py> {
644 list: Bound<'py, PyList>,
645 index: usize,
646 length: usize,
647}
648
649impl<'py> BoundListIterator<'py> {
650 fn new(list: Bound<'py, PyList>) -> Self {
651 let length: usize = list.len();
652 BoundListIterator {
653 list,
654 index: 0,
655 length,
656 }
657 }
658
659 unsafe fn get_item(&self, index: usize) -> Bound<'py, PyAny> {
660 #[cfg(any(Py_LIMITED_API, PyPy))]
661 let item = self.list.get_item(index).expect("list.get failed");
662 #[cfg(not(any(Py_LIMITED_API, PyPy)))]
663 let item = self.list.get_item_unchecked(index);
664 item
665 }
666}
667
668impl<'py> Iterator for BoundListIterator<'py> {
669 type Item = Bound<'py, PyAny>;
670
671 #[inline]
672 fn next(&mut self) -> Option<Self::Item> {
673 let length = self.length.min(self.list.len());
674
675 if self.index < length {
676 let item = unsafe { self.get_item(self.index) };
677 self.index += 1;
678 Some(item)
679 } else {
680 None
681 }
682 }
683
684 #[inline]
685 fn size_hint(&self) -> (usize, Option<usize>) {
686 let len = self.len();
687 (len, Some(len))
688 }
689}
690
691impl DoubleEndedIterator for BoundListIterator<'_> {
692 #[inline]
693 fn next_back(&mut self) -> Option<Self::Item> {
694 let length = self.length.min(self.list.len());
695
696 if self.index < length {
697 let item = unsafe { self.get_item(length - 1) };
698 self.length = length - 1;
699 Some(item)
700 } else {
701 None
702 }
703 }
704}
705
706impl ExactSizeIterator for BoundListIterator<'_> {
707 fn len(&self) -> usize {
708 self.length.saturating_sub(self.index)
709 }
710}
711
712impl FusedIterator for BoundListIterator<'_> {}
713
714impl<'py> IntoIterator for Bound<'py, PyList> {
715 type Item = Bound<'py, PyAny>;
716 type IntoIter = BoundListIterator<'py>;
717
718 fn into_iter(self) -> Self::IntoIter {
719 BoundListIterator::new(self)
720 }
721}
722
723impl<'py> IntoIterator for &Bound<'py, PyList> {
724 type Item = Bound<'py, PyAny>;
725 type IntoIter = BoundListIterator<'py>;
726
727 fn into_iter(self) -> Self::IntoIter {
728 self.iter()
729 }
730}
731
732#[cfg(test)]
733mod tests {
734 use crate::types::any::PyAnyMethods;
735 use crate::types::list::PyListMethods;
736 use crate::types::sequence::PySequenceMethods;
737 use crate::types::{PyList, PyTuple};
738 use crate::Python;
739 use crate::{IntoPy, PyObject, ToPyObject};
740
741 #[test]
742 fn test_new() {
743 Python::with_gil(|py| {
744 let list = PyList::new_bound(py, [2, 3, 5, 7]);
745 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
746 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
747 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
748 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
749 });
750 }
751
752 #[test]
753 fn test_len() {
754 Python::with_gil(|py| {
755 let list = PyList::new_bound(py, [1, 2, 3, 4]);
756 assert_eq!(4, list.len());
757 });
758 }
759
760 #[test]
761 fn test_get_item() {
762 Python::with_gil(|py| {
763 let list = PyList::new_bound(py, [2, 3, 5, 7]);
764 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
765 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
766 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
767 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
768 });
769 }
770
771 #[test]
772 fn test_get_slice() {
773 Python::with_gil(|py| {
774 let list = PyList::new_bound(py, [2, 3, 5, 7]);
775 let slice = list.get_slice(1, 3);
776 assert_eq!(2, slice.len());
777 let slice = list.get_slice(1, 7);
778 assert_eq!(3, slice.len());
779 });
780 }
781
782 #[test]
783 fn test_set_item() {
784 Python::with_gil(|py| {
785 let list = PyList::new_bound(py, [2, 3, 5, 7]);
786 let val = 42i32.to_object(py);
787 let val2 = 42i32.to_object(py);
788 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
789 list.set_item(0, val).unwrap();
790 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
791 assert!(list.set_item(10, val2).is_err());
792 });
793 }
794
795 #[test]
796 fn test_set_item_refcnt() {
797 Python::with_gil(|py| {
798 let obj = py.eval_bound("object()", None, None).unwrap();
799 let cnt;
800 {
801 let v = vec![2];
802 let ob = v.to_object(py);
803 let list = ob.downcast_bound::<PyList>(py).unwrap();
804 cnt = obj.get_refcnt();
805 list.set_item(0, &obj).unwrap();
806 }
807
808 assert_eq!(cnt, obj.get_refcnt());
809 });
810 }
811
812 #[test]
813 fn test_insert() {
814 Python::with_gil(|py| {
815 let list = PyList::new_bound(py, [2, 3, 5, 7]);
816 let val = 42i32.to_object(py);
817 let val2 = 43i32.to_object(py);
818 assert_eq!(4, list.len());
819 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
820 list.insert(0, val).unwrap();
821 list.insert(1000, val2).unwrap();
822 assert_eq!(6, list.len());
823 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
824 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
825 assert_eq!(43, list.get_item(5).unwrap().extract::<i32>().unwrap());
826 });
827 }
828
829 #[test]
830 fn test_insert_refcnt() {
831 Python::with_gil(|py| {
832 let cnt;
833 let obj = py.eval_bound("object()", None, None).unwrap();
834 {
835 let list = PyList::empty_bound(py);
836 cnt = obj.get_refcnt();
837 list.insert(0, &obj).unwrap();
838 }
839
840 assert_eq!(cnt, obj.get_refcnt());
841 });
842 }
843
844 #[test]
845 fn test_append() {
846 Python::with_gil(|py| {
847 let list = PyList::new_bound(py, [2]);
848 list.append(3).unwrap();
849 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
850 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
851 });
852 }
853
854 #[test]
855 fn test_append_refcnt() {
856 Python::with_gil(|py| {
857 let cnt;
858 let obj = py.eval_bound("object()", None, None).unwrap();
859 {
860 let list = PyList::empty_bound(py);
861 cnt = obj.get_refcnt();
862 list.append(&obj).unwrap();
863 }
864 assert_eq!(cnt, obj.get_refcnt());
865 });
866 }
867
868 #[test]
869 fn test_iter() {
870 Python::with_gil(|py| {
871 let v = vec![2, 3, 5, 7];
872 let list = PyList::new_bound(py, &v);
873 let mut idx = 0;
874 for el in list {
875 assert_eq!(v[idx], el.extract::<i32>().unwrap());
876 idx += 1;
877 }
878 assert_eq!(idx, v.len());
879 });
880 }
881
882 #[test]
883 fn test_iter_size_hint() {
884 Python::with_gil(|py| {
885 let v = vec![2, 3, 5, 7];
886 let ob = v.to_object(py);
887 let list = ob.downcast_bound::<PyList>(py).unwrap();
888
889 let mut iter = list.iter();
890 assert_eq!(iter.size_hint(), (v.len(), Some(v.len())));
891 iter.next();
892 assert_eq!(iter.size_hint(), (v.len() - 1, Some(v.len() - 1)));
893
894 for _ in &mut iter {}
896
897 assert_eq!(iter.size_hint(), (0, Some(0)));
898 });
899 }
900
901 #[test]
902 fn test_iter_rev() {
903 Python::with_gil(|py| {
904 let v = vec![2, 3, 5, 7];
905 let ob = v.to_object(py);
906 let list = ob.downcast_bound::<PyList>(py).unwrap();
907
908 let mut iter = list.iter().rev();
909
910 assert_eq!(iter.size_hint(), (4, Some(4)));
911
912 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 7);
913 assert_eq!(iter.size_hint(), (3, Some(3)));
914
915 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 5);
916 assert_eq!(iter.size_hint(), (2, Some(2)));
917
918 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
919 assert_eq!(iter.size_hint(), (1, Some(1)));
920
921 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 2);
922 assert_eq!(iter.size_hint(), (0, Some(0)));
923
924 assert!(iter.next().is_none());
925 assert!(iter.next().is_none());
926 });
927 }
928
929 #[test]
930 fn test_into_iter() {
931 Python::with_gil(|py| {
932 let list = PyList::new_bound(py, [1, 2, 3, 4]);
933 for (i, item) in list.iter().enumerate() {
934 assert_eq!((i + 1) as i32, item.extract::<i32>().unwrap());
935 }
936 });
937 }
938
939 #[test]
940 fn test_into_iter_bound() {
941 use crate::types::any::PyAnyMethods;
942
943 Python::with_gil(|py| {
944 let list = PyList::new_bound(py, [1, 2, 3, 4]);
945 let mut items = vec![];
946 for item in &list {
947 items.push(item.extract::<i32>().unwrap());
948 }
949 assert_eq!(items, vec![1, 2, 3, 4]);
950 });
951 }
952
953 #[test]
954 fn test_as_sequence() {
955 Python::with_gil(|py| {
956 let list = PyList::new_bound(py, [1, 2, 3, 4]);
957
958 assert_eq!(list.as_sequence().len().unwrap(), 4);
959 assert_eq!(
960 list.as_sequence()
961 .get_item(1)
962 .unwrap()
963 .extract::<i32>()
964 .unwrap(),
965 2
966 );
967 });
968 }
969
970 #[test]
971 fn test_into_sequence() {
972 Python::with_gil(|py| {
973 let list = PyList::new_bound(py, [1, 2, 3, 4]);
974
975 let sequence = list.into_sequence();
976
977 assert_eq!(sequence.len().unwrap(), 4);
978 assert_eq!(sequence.get_item(1).unwrap().extract::<i32>().unwrap(), 2);
979 });
980 }
981
982 #[test]
983 fn test_extract() {
984 Python::with_gil(|py| {
985 let v = vec![2, 3, 5, 7];
986 let list = PyList::new_bound(py, &v);
987 let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
988 assert_eq!(v, v2);
989 });
990 }
991
992 #[test]
993 fn test_sort() {
994 Python::with_gil(|py| {
995 let v = vec![7, 3, 2, 5];
996 let list = PyList::new_bound(py, &v);
997 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
998 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
999 assert_eq!(2, list.get_item(2).unwrap().extract::<i32>().unwrap());
1000 assert_eq!(5, list.get_item(3).unwrap().extract::<i32>().unwrap());
1001 list.sort().unwrap();
1002 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1003 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1004 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1005 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1006 });
1007 }
1008
1009 #[test]
1010 fn test_reverse() {
1011 Python::with_gil(|py| {
1012 let v = vec![2, 3, 5, 7];
1013 let list = PyList::new_bound(py, &v);
1014 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1015 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1016 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1017 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1018 list.reverse().unwrap();
1019 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1020 assert_eq!(5, list.get_item(1).unwrap().extract::<i32>().unwrap());
1021 assert_eq!(3, list.get_item(2).unwrap().extract::<i32>().unwrap());
1022 assert_eq!(2, list.get_item(3).unwrap().extract::<i32>().unwrap());
1023 });
1024 }
1025
1026 #[test]
1027 fn test_array_into_py() {
1028 Python::with_gil(|py| {
1029 let array: PyObject = [1, 2].into_py(py);
1030 let list = array.downcast_bound::<PyList>(py).unwrap();
1031 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1032 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
1033 });
1034 }
1035
1036 #[test]
1037 fn test_list_get_item_invalid_index() {
1038 Python::with_gil(|py| {
1039 let list = PyList::new_bound(py, [2, 3, 5, 7]);
1040 let obj = list.get_item(5);
1041 assert!(obj.is_err());
1042 assert_eq!(
1043 obj.unwrap_err().to_string(),
1044 "IndexError: list index out of range"
1045 );
1046 });
1047 }
1048
1049 #[test]
1050 fn test_list_get_item_sanity() {
1051 Python::with_gil(|py| {
1052 let list = PyList::new_bound(py, [2, 3, 5, 7]);
1053 let obj = list.get_item(0);
1054 assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
1055 });
1056 }
1057
1058 #[cfg(not(any(Py_LIMITED_API, PyPy)))]
1059 #[test]
1060 fn test_list_get_item_unchecked_sanity() {
1061 Python::with_gil(|py| {
1062 let list = PyList::new_bound(py, [2, 3, 5, 7]);
1063 let obj = unsafe { list.get_item_unchecked(0) };
1064 assert_eq!(obj.extract::<i32>().unwrap(), 2);
1065 });
1066 }
1067
1068 #[test]
1069 #[cfg(feature = "gil-refs")]
1070 #[allow(deprecated)]
1071 fn test_list_index_trait() {
1072 Python::with_gil(|py| {
1073 let list = PyList::new(py, [2, 3, 5]);
1074 assert_eq!(2, list[0].extract::<i32>().unwrap());
1075 assert_eq!(3, list[1].extract::<i32>().unwrap());
1076 assert_eq!(5, list[2].extract::<i32>().unwrap());
1077 });
1078 }
1079
1080 #[test]
1081 #[should_panic]
1082 #[cfg(feature = "gil-refs")]
1083 #[allow(deprecated)]
1084 fn test_list_index_trait_panic() {
1085 Python::with_gil(|py| {
1086 let list = PyList::new(py, [2, 3, 5]);
1087 let _ = &list[7];
1088 });
1089 }
1090
1091 #[test]
1092 #[cfg(feature = "gil-refs")]
1093 #[allow(deprecated)]
1094 fn test_list_index_trait_ranges() {
1095 Python::with_gil(|py| {
1096 let list = PyList::new(py, [2, 3, 5]);
1097 assert_eq!(vec![3, 5], list[1..3].extract::<Vec<i32>>().unwrap());
1098 assert_eq!(Vec::<i32>::new(), list[3..3].extract::<Vec<i32>>().unwrap());
1099 assert_eq!(vec![3, 5], list[1..].extract::<Vec<i32>>().unwrap());
1100 assert_eq!(Vec::<i32>::new(), list[3..].extract::<Vec<i32>>().unwrap());
1101 assert_eq!(vec![2, 3, 5], list[..].extract::<Vec<i32>>().unwrap());
1102 assert_eq!(vec![3, 5], list[1..=2].extract::<Vec<i32>>().unwrap());
1103 assert_eq!(vec![2, 3], list[..2].extract::<Vec<i32>>().unwrap());
1104 assert_eq!(vec![2, 3], list[..=1].extract::<Vec<i32>>().unwrap());
1105 })
1106 }
1107
1108 #[test]
1109 #[should_panic = "range start index 5 out of range for list of length 3"]
1110 #[cfg(feature = "gil-refs")]
1111 #[allow(deprecated)]
1112 fn test_list_index_trait_range_panic_start() {
1113 Python::with_gil(|py| {
1114 let list = PyList::new(py, [2, 3, 5]);
1115 list[5..10].extract::<Vec<i32>>().unwrap();
1116 })
1117 }
1118
1119 #[test]
1120 #[should_panic = "range end index 10 out of range for list of length 3"]
1121 #[cfg(feature = "gil-refs")]
1122 #[allow(deprecated)]
1123 fn test_list_index_trait_range_panic_end() {
1124 Python::with_gil(|py| {
1125 let list = PyList::new(py, [2, 3, 5]);
1126 list[1..10].extract::<Vec<i32>>().unwrap();
1127 })
1128 }
1129
1130 #[test]
1131 #[should_panic = "slice index starts at 2 but ends at 1"]
1132 #[cfg(feature = "gil-refs")]
1133 #[allow(deprecated)]
1134 fn test_list_index_trait_range_panic_wrong_order() {
1135 Python::with_gil(|py| {
1136 let list = PyList::new(py, [2, 3, 5]);
1137 #[allow(clippy::reversed_empty_ranges)]
1138 list[2..1].extract::<Vec<i32>>().unwrap();
1139 })
1140 }
1141
1142 #[test]
1143 #[should_panic = "range start index 8 out of range for list of length 3"]
1144 #[cfg(feature = "gil-refs")]
1145 #[allow(deprecated)]
1146 fn test_list_index_trait_range_from_panic() {
1147 Python::with_gil(|py| {
1148 let list = PyList::new(py, [2, 3, 5]);
1149 list[8..].extract::<Vec<i32>>().unwrap();
1150 })
1151 }
1152
1153 #[test]
1154 fn test_list_del_item() {
1155 Python::with_gil(|py| {
1156 let list = PyList::new_bound(py, [1, 1, 2, 3, 5, 8]);
1157 assert!(list.del_item(10).is_err());
1158 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1159 assert!(list.del_item(0).is_ok());
1160 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1161 assert!(list.del_item(0).is_ok());
1162 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1163 assert!(list.del_item(0).is_ok());
1164 assert_eq!(3, list.get_item(0).unwrap().extract::<i32>().unwrap());
1165 assert!(list.del_item(0).is_ok());
1166 assert_eq!(5, list.get_item(0).unwrap().extract::<i32>().unwrap());
1167 assert!(list.del_item(0).is_ok());
1168 assert_eq!(8, list.get_item(0).unwrap().extract::<i32>().unwrap());
1169 assert!(list.del_item(0).is_ok());
1170 assert_eq!(0, list.len());
1171 assert!(list.del_item(0).is_err());
1172 });
1173 }
1174
1175 #[test]
1176 fn test_list_set_slice() {
1177 Python::with_gil(|py| {
1178 let list = PyList::new_bound(py, [1, 1, 2, 3, 5, 8]);
1179 let ins = PyList::new_bound(py, [7, 4]);
1180 list.set_slice(1, 4, &ins).unwrap();
1181 assert_eq!([1, 7, 4, 5, 8], list.extract::<[i32; 5]>().unwrap());
1182 list.set_slice(3, 100, &PyList::empty_bound(py)).unwrap();
1183 assert_eq!([1, 7, 4], list.extract::<[i32; 3]>().unwrap());
1184 });
1185 }
1186
1187 #[test]
1188 fn test_list_del_slice() {
1189 Python::with_gil(|py| {
1190 let list = PyList::new_bound(py, [1, 1, 2, 3, 5, 8]);
1191 list.del_slice(1, 4).unwrap();
1192 assert_eq!([1, 5, 8], list.extract::<[i32; 3]>().unwrap());
1193 list.del_slice(1, 100).unwrap();
1194 assert_eq!([1], list.extract::<[i32; 1]>().unwrap());
1195 });
1196 }
1197
1198 #[test]
1199 fn test_list_contains() {
1200 Python::with_gil(|py| {
1201 let list = PyList::new_bound(py, [1, 1, 2, 3, 5, 8]);
1202 assert_eq!(6, list.len());
1203
1204 let bad_needle = 7i32.to_object(py);
1205 assert!(!list.contains(&bad_needle).unwrap());
1206
1207 let good_needle = 8i32.to_object(py);
1208 assert!(list.contains(&good_needle).unwrap());
1209
1210 let type_coerced_needle = 8f32.to_object(py);
1211 assert!(list.contains(&type_coerced_needle).unwrap());
1212 });
1213 }
1214
1215 #[test]
1216 fn test_list_index() {
1217 Python::with_gil(|py| {
1218 let list = PyList::new_bound(py, [1, 1, 2, 3, 5, 8]);
1219 assert_eq!(0, list.index(1i32).unwrap());
1220 assert_eq!(2, list.index(2i32).unwrap());
1221 assert_eq!(3, list.index(3i32).unwrap());
1222 assert_eq!(4, list.index(5i32).unwrap());
1223 assert_eq!(5, list.index(8i32).unwrap());
1224 assert!(list.index(42i32).is_err());
1225 });
1226 }
1227
1228 use std::ops::Range;
1229
1230 struct FaultyIter(Range<usize>, usize);
1233
1234 impl Iterator for FaultyIter {
1235 type Item = usize;
1236
1237 fn next(&mut self) -> Option<Self::Item> {
1238 self.0.next()
1239 }
1240 }
1241
1242 impl ExactSizeIterator for FaultyIter {
1243 fn len(&self) -> usize {
1244 self.1
1245 }
1246 }
1247
1248 #[test]
1249 #[should_panic(
1250 expected = "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation."
1251 )]
1252 fn too_long_iterator() {
1253 Python::with_gil(|py| {
1254 let iter = FaultyIter(0..usize::MAX, 73);
1255 let _list = PyList::new_bound(py, iter);
1256 })
1257 }
1258
1259 #[test]
1260 #[should_panic(
1261 expected = "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation."
1262 )]
1263 fn too_short_iterator() {
1264 Python::with_gil(|py| {
1265 let iter = FaultyIter(0..35, 73);
1266 let _list = PyList::new_bound(py, iter);
1267 })
1268 }
1269
1270 #[test]
1271 #[should_panic(
1272 expected = "out of range integral type conversion attempted on `elements.len()`"
1273 )]
1274 fn overflowing_size() {
1275 Python::with_gil(|py| {
1276 let iter = FaultyIter(0..0, usize::MAX);
1277
1278 let _list = PyList::new_bound(py, iter);
1279 })
1280 }
1281
1282 #[cfg(feature = "macros")]
1283 #[test]
1284 fn bad_clone_mem_leaks() {
1285 use crate::{Py, PyAny};
1286 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1287 static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0);
1288
1289 #[crate::pyclass]
1290 #[pyo3(crate = "crate")]
1291 struct Bad(usize);
1292
1293 impl Clone for Bad {
1294 fn clone(&self) -> Self {
1295 assert_ne!(self.0, 42);
1297 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
1298
1299 Bad(self.0)
1300 }
1301 }
1302
1303 impl Drop for Bad {
1304 fn drop(&mut self) {
1305 NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst);
1306 }
1307 }
1308
1309 impl ToPyObject for Bad {
1310 fn to_object(&self, py: Python<'_>) -> Py<PyAny> {
1311 self.to_owned().into_py(py)
1312 }
1313 }
1314
1315 struct FaultyIter(Range<usize>, usize);
1316
1317 impl Iterator for FaultyIter {
1318 type Item = Bad;
1319
1320 fn next(&mut self) -> Option<Self::Item> {
1321 self.0.next().map(|i| {
1322 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
1323 Bad(i)
1324 })
1325 }
1326 }
1327
1328 impl ExactSizeIterator for FaultyIter {
1329 fn len(&self) -> usize {
1330 self.1
1331 }
1332 }
1333
1334 Python::with_gil(|py| {
1335 std::panic::catch_unwind(|| {
1336 let iter = FaultyIter(0..50, 50);
1337 let _list = PyList::new_bound(py, iter);
1338 })
1339 .unwrap_err();
1340 });
1341
1342 assert_eq!(
1343 NEEDS_DESTRUCTING_COUNT.load(SeqCst),
1344 0,
1345 "Some destructors did not run"
1346 );
1347 }
1348
1349 #[test]
1350 fn test_list_to_tuple() {
1351 Python::with_gil(|py| {
1352 let list = PyList::new_bound(py, vec![1, 2, 3]);
1353 let tuple = list.to_tuple();
1354 let tuple_expected = PyTuple::new_bound(py, vec![1, 2, 3]);
1355 assert!(tuple.eq(tuple_expected).unwrap());
1356 })
1357 }
1358}