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};
8use crate::{
9 Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr, PyObject, Python,
10};
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(
30 py: Python<'_>,
31 elements: impl ExactSizeIterator<Item = PyObject>,
32) -> Bound<'_, PyList> {
33 try_new_from_iter(py, elements.map(|e| e.into_bound(py)).map(Ok)).unwrap()
34}
35
36#[inline]
37#[track_caller]
38pub(crate) fn try_new_from_iter<'py>(
39 py: Python<'py>,
40 mut elements: impl ExactSizeIterator<Item = PyResult<Bound<'py, PyAny>>>,
41) -> PyResult<Bound<'py, PyList>> {
42 unsafe {
43 let len: Py_ssize_t = elements
45 .len()
46 .try_into()
47 .expect("out of range integral type conversion attempted on `elements.len()`");
48
49 let ptr = ffi::PyList_New(len);
50
51 let list = ptr.assume_owned(py).downcast_into_unchecked();
55
56 let count = (&mut elements)
57 .take(len as usize)
58 .try_fold(0, |count, item| {
59 #[cfg(not(Py_LIMITED_API))]
60 ffi::PyList_SET_ITEM(ptr, count, item?.into_ptr());
61 #[cfg(Py_LIMITED_API)]
62 ffi::PyList_SetItem(ptr, count, item?.into_ptr());
63 Ok::<_, PyErr>(count + 1)
64 })?;
65
66 assert!(elements.next().is_none(), "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation.");
67 assert_eq!(len, count, "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation.");
68
69 Ok(list)
70 }
71}
72
73impl PyList {
74 #[track_caller]
101 pub fn new<'py, T, U>(
102 py: Python<'py>,
103 elements: impl IntoIterator<Item = T, IntoIter = U>,
104 ) -> PyResult<Bound<'py, PyList>>
105 where
106 T: IntoPyObject<'py>,
107 U: ExactSizeIterator<Item = T>,
108 {
109 let iter = elements.into_iter().map(|e| e.into_bound_py_any(py));
110 try_new_from_iter(py, iter)
111 }
112
113 #[deprecated(since = "0.23.0", note = "renamed to `PyList::new`")]
115 #[allow(deprecated)]
116 #[inline]
117 #[track_caller]
118 pub fn new_bound<T, U>(
119 py: Python<'_>,
120 elements: impl IntoIterator<Item = T, IntoIter = U>,
121 ) -> Bound<'_, PyList>
122 where
123 T: crate::ToPyObject,
124 U: ExactSizeIterator<Item = T>,
125 {
126 Self::new(py, elements.into_iter().map(|e| e.to_object(py))).unwrap()
127 }
128
129 pub fn empty(py: Python<'_>) -> Bound<'_, PyList> {
131 unsafe {
132 ffi::PyList_New(0)
133 .assume_owned(py)
134 .downcast_into_unchecked()
135 }
136 }
137
138 #[deprecated(since = "0.23.0", note = "renamed to `PyList::empty`")]
140 #[inline]
141 pub fn empty_bound(py: Python<'_>) -> Bound<'_, PyList> {
142 Self::empty(py)
143 }
144}
145
146#[doc(alias = "PyList")]
152pub trait PyListMethods<'py>: crate::sealed::Sealed {
153 fn len(&self) -> usize;
155
156 fn is_empty(&self) -> bool;
158
159 fn as_sequence(&self) -> &Bound<'py, PySequence>;
161
162 fn into_sequence(self) -> Bound<'py, PySequence>;
164
165 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
176
177 #[cfg(not(Py_LIMITED_API))]
185 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny>;
186
187 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList>;
192
193 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
197 where
198 I: IntoPyObject<'py>;
199
200 fn del_item(&self, index: usize) -> PyResult<()>;
204
205 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()>;
209
210 fn del_slice(&self, low: usize, high: usize) -> PyResult<()>;
214
215 fn append<I>(&self, item: I) -> PyResult<()>
217 where
218 I: IntoPyObject<'py>;
219
220 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
224 where
225 I: IntoPyObject<'py>;
226
227 fn contains<V>(&self, value: V) -> PyResult<bool>
231 where
232 V: IntoPyObject<'py>;
233
234 fn index<V>(&self, value: V) -> PyResult<usize>
238 where
239 V: IntoPyObject<'py>;
240
241 fn iter(&self) -> BoundListIterator<'py>;
243
244 fn locked_for_each<F>(&self, closure: F) -> PyResult<()>
252 where
253 F: Fn(Bound<'py, PyAny>) -> PyResult<()>;
254
255 fn sort(&self) -> PyResult<()>;
257
258 fn reverse(&self) -> PyResult<()>;
260
261 fn to_tuple(&self) -> Bound<'py, PyTuple>;
265}
266
267impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
268 fn len(&self) -> usize {
270 unsafe {
271 #[cfg(not(Py_LIMITED_API))]
272 let size = ffi::PyList_GET_SIZE(self.as_ptr());
273 #[cfg(Py_LIMITED_API)]
274 let size = ffi::PyList_Size(self.as_ptr());
275
276 size as usize
278 }
279 }
280
281 fn is_empty(&self) -> bool {
283 self.len() == 0
284 }
285
286 fn as_sequence(&self) -> &Bound<'py, PySequence> {
288 unsafe { self.downcast_unchecked() }
289 }
290
291 fn into_sequence(self) -> Bound<'py, PySequence> {
293 unsafe { self.into_any().downcast_into_unchecked() }
294 }
295
296 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
307 unsafe {
308 ffi::compat::PyList_GetItemRef(self.as_ptr(), index as Py_ssize_t)
309 .assume_owned_or_err(self.py())
310 }
311 }
312
313 #[cfg(not(Py_LIMITED_API))]
319 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny> {
320 ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t)
322 .assume_borrowed(self.py())
323 .to_owned()
324 }
325
326 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList> {
331 unsafe {
332 ffi::PyList_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
333 .assume_owned(self.py())
334 .downcast_into_unchecked()
335 }
336 }
337
338 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
342 where
343 I: IntoPyObject<'py>,
344 {
345 fn inner(list: &Bound<'_, PyList>, index: usize, item: Bound<'_, PyAny>) -> PyResult<()> {
346 err::error_on_minusone(list.py(), unsafe {
347 ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
348 })
349 }
350
351 let py = self.py();
352 inner(self, index, item.into_bound_py_any(py)?)
353 }
354
355 #[inline]
359 fn del_item(&self, index: usize) -> PyResult<()> {
360 self.as_sequence().del_item(index)
361 }
362
363 #[inline]
367 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()> {
368 err::error_on_minusone(self.py(), unsafe {
369 ffi::PyList_SetSlice(
370 self.as_ptr(),
371 get_ssize_index(low),
372 get_ssize_index(high),
373 seq.as_ptr(),
374 )
375 })
376 }
377
378 #[inline]
382 fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
383 self.as_sequence().del_slice(low, high)
384 }
385
386 fn append<I>(&self, item: I) -> PyResult<()>
388 where
389 I: IntoPyObject<'py>,
390 {
391 fn inner(list: &Bound<'_, PyList>, item: Borrowed<'_, '_, PyAny>) -> PyResult<()> {
392 err::error_on_minusone(list.py(), unsafe {
393 ffi::PyList_Append(list.as_ptr(), item.as_ptr())
394 })
395 }
396
397 let py = self.py();
398 inner(
399 self,
400 item.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
401 )
402 }
403
404 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
408 where
409 I: IntoPyObject<'py>,
410 {
411 fn inner(
412 list: &Bound<'_, PyList>,
413 index: usize,
414 item: Borrowed<'_, '_, PyAny>,
415 ) -> PyResult<()> {
416 err::error_on_minusone(list.py(), unsafe {
417 ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
418 })
419 }
420
421 let py = self.py();
422 inner(
423 self,
424 index,
425 item.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
426 )
427 }
428
429 #[inline]
433 fn contains<V>(&self, value: V) -> PyResult<bool>
434 where
435 V: IntoPyObject<'py>,
436 {
437 self.as_sequence().contains(value)
438 }
439
440 #[inline]
444 fn index<V>(&self, value: V) -> PyResult<usize>
445 where
446 V: IntoPyObject<'py>,
447 {
448 self.as_sequence().index(value)
449 }
450
451 fn iter(&self) -> BoundListIterator<'py> {
453 BoundListIterator::new(self.clone())
454 }
455
456 fn locked_for_each<F>(&self, closure: F) -> PyResult<()>
458 where
459 F: Fn(Bound<'py, PyAny>) -> PyResult<()>,
460 {
461 crate::sync::with_critical_section(self, || self.iter().try_for_each(closure))
462 }
463
464 fn sort(&self) -> PyResult<()> {
466 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
467 }
468
469 fn reverse(&self) -> PyResult<()> {
471 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
472 }
473
474 fn to_tuple(&self) -> Bound<'py, PyTuple> {
478 unsafe {
479 ffi::PyList_AsTuple(self.as_ptr())
480 .assume_owned(self.py())
481 .downcast_into_unchecked()
482 }
483 }
484}
485
486struct Index(usize);
489struct Length(usize);
490
491pub struct BoundListIterator<'py> {
493 list: Bound<'py, PyList>,
494 index: Index,
495 length: Length,
496}
497
498impl<'py> BoundListIterator<'py> {
499 fn new(list: Bound<'py, PyList>) -> Self {
500 Self {
501 index: Index(0),
502 length: Length(list.len()),
503 list,
504 }
505 }
506
507 #[inline]
513 #[cfg(not(Py_LIMITED_API))]
514 #[deny(unsafe_op_in_unsafe_fn)]
515 unsafe fn next_unchecked(
516 index: &mut Index,
517 length: &mut Length,
518 list: &Bound<'py, PyList>,
519 ) -> Option<Bound<'py, PyAny>> {
520 let length = length.0.min(list.len());
521 let my_index = index.0;
522
523 if index.0 < length {
524 let item = unsafe { list.get_item_unchecked(my_index) };
525 index.0 += 1;
526 Some(item)
527 } else {
528 None
529 }
530 }
531
532 #[cfg(Py_LIMITED_API)]
533 fn next(
534 index: &mut Index,
535 length: &mut Length,
536 list: &Bound<'py, PyList>,
537 ) -> Option<Bound<'py, PyAny>> {
538 let length = length.0.min(list.len());
539 let my_index = index.0;
540
541 if index.0 < length {
542 let item = list.get_item(my_index).expect("get-item failed");
543 index.0 += 1;
544 Some(item)
545 } else {
546 None
547 }
548 }
549
550 #[inline]
556 #[cfg(not(Py_LIMITED_API))]
557 #[deny(unsafe_op_in_unsafe_fn)]
558 unsafe fn next_back_unchecked(
559 index: &mut Index,
560 length: &mut Length,
561 list: &Bound<'py, PyList>,
562 ) -> Option<Bound<'py, PyAny>> {
563 let current_length = length.0.min(list.len());
564
565 if index.0 < current_length {
566 let item = unsafe { list.get_item_unchecked(current_length - 1) };
567 length.0 = current_length - 1;
568 Some(item)
569 } else {
570 None
571 }
572 }
573
574 #[inline]
575 #[cfg(Py_LIMITED_API)]
576 fn next_back(
577 index: &mut Index,
578 length: &mut Length,
579 list: &Bound<'py, PyList>,
580 ) -> Option<Bound<'py, PyAny>> {
581 let current_length = (length.0).min(list.len());
582
583 if index.0 < current_length {
584 let item = list.get_item(current_length - 1).expect("get-item failed");
585 length.0 = current_length - 1;
586 Some(item)
587 } else {
588 None
589 }
590 }
591
592 #[cfg(not(Py_LIMITED_API))]
593 fn with_critical_section<R>(
594 &mut self,
595 f: impl FnOnce(&mut Index, &mut Length, &Bound<'py, PyList>) -> R,
596 ) -> R {
597 let Self {
598 index,
599 length,
600 list,
601 } = self;
602 crate::sync::with_critical_section(list, || f(index, length, list))
603 }
604}
605
606impl<'py> Iterator for BoundListIterator<'py> {
607 type Item = Bound<'py, PyAny>;
608
609 #[inline]
610 fn next(&mut self) -> Option<Self::Item> {
611 #[cfg(not(Py_LIMITED_API))]
612 {
613 self.with_critical_section(|index, length, list| unsafe {
614 Self::next_unchecked(index, length, list)
615 })
616 }
617 #[cfg(Py_LIMITED_API)]
618 {
619 let Self {
620 index,
621 length,
622 list,
623 } = self;
624 Self::next(index, length, list)
625 }
626 }
627
628 #[inline]
629 fn size_hint(&self) -> (usize, Option<usize>) {
630 let len = self.len();
631 (len, Some(len))
632 }
633
634 #[inline]
635 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
636 fn fold<B, F>(mut self, init: B, mut f: F) -> B
637 where
638 Self: Sized,
639 F: FnMut(B, Self::Item) -> B,
640 {
641 self.with_critical_section(|index, length, list| {
642 let mut accum = init;
643 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
644 accum = f(accum, x);
645 }
646 accum
647 })
648 }
649
650 #[inline]
651 #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
652 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
653 where
654 Self: Sized,
655 F: FnMut(B, Self::Item) -> R,
656 R: std::ops::Try<Output = B>,
657 {
658 self.with_critical_section(|index, length, list| {
659 let mut accum = init;
660 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
661 accum = f(accum, x)?
662 }
663 R::from_output(accum)
664 })
665 }
666
667 #[inline]
668 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
669 fn all<F>(&mut self, mut f: F) -> bool
670 where
671 Self: Sized,
672 F: FnMut(Self::Item) -> bool,
673 {
674 self.with_critical_section(|index, length, list| {
675 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
676 if !f(x) {
677 return false;
678 }
679 }
680 true
681 })
682 }
683
684 #[inline]
685 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
686 fn any<F>(&mut self, mut f: F) -> bool
687 where
688 Self: Sized,
689 F: FnMut(Self::Item) -> bool,
690 {
691 self.with_critical_section(|index, length, list| {
692 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
693 if f(x) {
694 return true;
695 }
696 }
697 false
698 })
699 }
700
701 #[inline]
702 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
703 fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
704 where
705 Self: Sized,
706 P: FnMut(&Self::Item) -> bool,
707 {
708 self.with_critical_section(|index, length, list| {
709 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
710 if predicate(&x) {
711 return Some(x);
712 }
713 }
714 None
715 })
716 }
717
718 #[inline]
719 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
720 fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
721 where
722 Self: Sized,
723 F: FnMut(Self::Item) -> Option<B>,
724 {
725 self.with_critical_section(|index, length, list| {
726 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
727 if let found @ Some(_) = f(x) {
728 return found;
729 }
730 }
731 None
732 })
733 }
734
735 #[inline]
736 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
737 fn position<P>(&mut self, mut predicate: P) -> Option<usize>
738 where
739 Self: Sized,
740 P: FnMut(Self::Item) -> bool,
741 {
742 self.with_critical_section(|index, length, list| {
743 let mut acc = 0;
744 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
745 if predicate(x) {
746 return Some(acc);
747 }
748 acc += 1;
749 }
750 None
751 })
752 }
753}
754
755impl DoubleEndedIterator for BoundListIterator<'_> {
756 #[inline]
757 fn next_back(&mut self) -> Option<Self::Item> {
758 #[cfg(not(Py_LIMITED_API))]
759 {
760 self.with_critical_section(|index, length, list| unsafe {
761 Self::next_back_unchecked(index, length, list)
762 })
763 }
764 #[cfg(Py_LIMITED_API)]
765 {
766 let Self {
767 index,
768 length,
769 list,
770 } = self;
771 Self::next_back(index, length, list)
772 }
773 }
774
775 #[inline]
776 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
777 fn rfold<B, F>(mut self, init: B, mut f: F) -> B
778 where
779 Self: Sized,
780 F: FnMut(B, Self::Item) -> B,
781 {
782 self.with_critical_section(|index, length, list| {
783 let mut accum = init;
784 while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
785 accum = f(accum, x);
786 }
787 accum
788 })
789 }
790
791 #[inline]
792 #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
793 fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
794 where
795 Self: Sized,
796 F: FnMut(B, Self::Item) -> R,
797 R: std::ops::Try<Output = B>,
798 {
799 self.with_critical_section(|index, length, list| {
800 let mut accum = init;
801 while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
802 accum = f(accum, x)?
803 }
804 R::from_output(accum)
805 })
806 }
807}
808
809impl ExactSizeIterator for BoundListIterator<'_> {
810 fn len(&self) -> usize {
811 self.length.0.saturating_sub(self.index.0)
812 }
813}
814
815impl FusedIterator for BoundListIterator<'_> {}
816
817impl<'py> IntoIterator for Bound<'py, PyList> {
818 type Item = Bound<'py, PyAny>;
819 type IntoIter = BoundListIterator<'py>;
820
821 fn into_iter(self) -> Self::IntoIter {
822 BoundListIterator::new(self)
823 }
824}
825
826impl<'py> IntoIterator for &Bound<'py, PyList> {
827 type Item = Bound<'py, PyAny>;
828 type IntoIter = BoundListIterator<'py>;
829
830 fn into_iter(self) -> Self::IntoIter {
831 self.iter()
832 }
833}
834
835#[cfg(test)]
836mod tests {
837 use crate::types::any::PyAnyMethods;
838 use crate::types::list::PyListMethods;
839 use crate::types::sequence::PySequenceMethods;
840 use crate::types::{PyList, PyTuple};
841 use crate::{ffi, IntoPyObject, PyResult, Python};
842
843 #[test]
844 fn test_new() {
845 Python::with_gil(|py| {
846 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
847 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
848 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
849 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
850 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
851 });
852 }
853
854 #[test]
855 fn test_len() {
856 Python::with_gil(|py| {
857 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
858 assert_eq!(4, list.len());
859 });
860 }
861
862 #[test]
863 fn test_get_item() {
864 Python::with_gil(|py| {
865 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
866 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
867 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
868 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
869 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
870 });
871 }
872
873 #[test]
874 fn test_get_slice() {
875 Python::with_gil(|py| {
876 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
877 let slice = list.get_slice(1, 3);
878 assert_eq!(2, slice.len());
879 let slice = list.get_slice(1, 7);
880 assert_eq!(3, slice.len());
881 });
882 }
883
884 #[test]
885 fn test_set_item() {
886 Python::with_gil(|py| {
887 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
888 let val = 42i32.into_pyobject(py).unwrap();
889 let val2 = 42i32.into_pyobject(py).unwrap();
890 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
891 list.set_item(0, val).unwrap();
892 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
893 assert!(list.set_item(10, val2).is_err());
894 });
895 }
896
897 #[test]
898 fn test_set_item_refcnt() {
899 Python::with_gil(|py| {
900 let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
901 let cnt;
902 {
903 let v = vec![2];
904 let ob = v.into_pyobject(py).unwrap();
905 let list = ob.downcast::<PyList>().unwrap();
906 cnt = obj.get_refcnt();
907 list.set_item(0, &obj).unwrap();
908 }
909
910 assert_eq!(cnt, obj.get_refcnt());
911 });
912 }
913
914 #[test]
915 fn test_insert() {
916 Python::with_gil(|py| {
917 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
918 let val = 42i32.into_pyobject(py).unwrap();
919 let val2 = 43i32.into_pyobject(py).unwrap();
920 assert_eq!(4, list.len());
921 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
922 list.insert(0, val).unwrap();
923 list.insert(1000, val2).unwrap();
924 assert_eq!(6, list.len());
925 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
926 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
927 assert_eq!(43, list.get_item(5).unwrap().extract::<i32>().unwrap());
928 });
929 }
930
931 #[test]
932 fn test_insert_refcnt() {
933 Python::with_gil(|py| {
934 let cnt;
935 let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
936 {
937 let list = PyList::empty(py);
938 cnt = obj.get_refcnt();
939 list.insert(0, &obj).unwrap();
940 }
941
942 assert_eq!(cnt, obj.get_refcnt());
943 });
944 }
945
946 #[test]
947 fn test_append() {
948 Python::with_gil(|py| {
949 let list = PyList::new(py, [2]).unwrap();
950 list.append(3).unwrap();
951 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
952 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
953 });
954 }
955
956 #[test]
957 fn test_append_refcnt() {
958 Python::with_gil(|py| {
959 let cnt;
960 let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
961 {
962 let list = PyList::empty(py);
963 cnt = obj.get_refcnt();
964 list.append(&obj).unwrap();
965 }
966 assert_eq!(cnt, obj.get_refcnt());
967 });
968 }
969
970 #[test]
971 fn test_iter() {
972 Python::with_gil(|py| {
973 let v = vec![2, 3, 5, 7];
974 let list = PyList::new(py, &v).unwrap();
975 let mut idx = 0;
976 for el in list {
977 assert_eq!(v[idx], el.extract::<i32>().unwrap());
978 idx += 1;
979 }
980 assert_eq!(idx, v.len());
981 });
982 }
983
984 #[test]
985 fn test_iter_size_hint() {
986 Python::with_gil(|py| {
987 let v = vec![2, 3, 5, 7];
988 let ob = (&v).into_pyobject(py).unwrap();
989 let list = ob.downcast::<PyList>().unwrap();
990
991 let mut iter = list.iter();
992 assert_eq!(iter.size_hint(), (v.len(), Some(v.len())));
993 iter.next();
994 assert_eq!(iter.size_hint(), (v.len() - 1, Some(v.len() - 1)));
995
996 for _ in &mut iter {}
998
999 assert_eq!(iter.size_hint(), (0, Some(0)));
1000 });
1001 }
1002
1003 #[test]
1004 fn test_iter_rev() {
1005 Python::with_gil(|py| {
1006 let v = vec![2, 3, 5, 7];
1007 let ob = v.into_pyobject(py).unwrap();
1008 let list = ob.downcast::<PyList>().unwrap();
1009
1010 let mut iter = list.iter().rev();
1011
1012 assert_eq!(iter.size_hint(), (4, Some(4)));
1013
1014 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 7);
1015 assert_eq!(iter.size_hint(), (3, Some(3)));
1016
1017 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 5);
1018 assert_eq!(iter.size_hint(), (2, Some(2)));
1019
1020 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
1021 assert_eq!(iter.size_hint(), (1, Some(1)));
1022
1023 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 2);
1024 assert_eq!(iter.size_hint(), (0, Some(0)));
1025
1026 assert!(iter.next().is_none());
1027 assert!(iter.next().is_none());
1028 });
1029 }
1030
1031 #[test]
1032 fn test_iter_all() {
1033 Python::with_gil(|py| {
1034 let list = PyList::new(py, [true, true, true]).unwrap();
1035 assert!(list.iter().all(|x| x.extract::<bool>().unwrap()));
1036
1037 let list = PyList::new(py, [true, false, true]).unwrap();
1038 assert!(!list.iter().all(|x| x.extract::<bool>().unwrap()));
1039 });
1040 }
1041
1042 #[test]
1043 fn test_iter_any() {
1044 Python::with_gil(|py| {
1045 let list = PyList::new(py, [true, true, true]).unwrap();
1046 assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1047
1048 let list = PyList::new(py, [true, false, true]).unwrap();
1049 assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1050
1051 let list = PyList::new(py, [false, false, false]).unwrap();
1052 assert!(!list.iter().any(|x| x.extract::<bool>().unwrap()));
1053 });
1054 }
1055
1056 #[test]
1057 fn test_iter_find() {
1058 Python::with_gil(|py: Python<'_>| {
1059 let list = PyList::new(py, ["hello", "world"]).unwrap();
1060 assert_eq!(
1061 Some("world".to_string()),
1062 list.iter()
1063 .find(|v| v.extract::<String>().unwrap() == "world")
1064 .map(|v| v.extract::<String>().unwrap())
1065 );
1066 assert_eq!(
1067 None,
1068 list.iter()
1069 .find(|v| v.extract::<String>().unwrap() == "foobar")
1070 .map(|v| v.extract::<String>().unwrap())
1071 );
1072 });
1073 }
1074
1075 #[test]
1076 fn test_iter_position() {
1077 Python::with_gil(|py: Python<'_>| {
1078 let list = PyList::new(py, ["hello", "world"]).unwrap();
1079 assert_eq!(
1080 Some(1),
1081 list.iter()
1082 .position(|v| v.extract::<String>().unwrap() == "world")
1083 );
1084 assert_eq!(
1085 None,
1086 list.iter()
1087 .position(|v| v.extract::<String>().unwrap() == "foobar")
1088 );
1089 });
1090 }
1091
1092 #[test]
1093 fn test_iter_fold() {
1094 Python::with_gil(|py: Python<'_>| {
1095 let list = PyList::new(py, [1, 2, 3]).unwrap();
1096 let sum = list
1097 .iter()
1098 .fold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1099 assert_eq!(sum, 6);
1100 });
1101 }
1102
1103 #[test]
1104 fn test_iter_fold_out_of_bounds() {
1105 Python::with_gil(|py: Python<'_>| {
1106 let list = PyList::new(py, [1, 2, 3]).unwrap();
1107 let sum = list.iter().fold(0, |_, _| {
1108 for _ in 0..3 {
1111 list.del_item(0).unwrap();
1112 }
1113 -5
1114 });
1115 assert_eq!(sum, -5);
1116 assert!(list.len() == 0);
1117 });
1118 }
1119
1120 #[test]
1121 fn test_iter_rfold() {
1122 Python::with_gil(|py: Python<'_>| {
1123 let list = PyList::new(py, [1, 2, 3]).unwrap();
1124 let sum = list
1125 .iter()
1126 .rfold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1127 assert_eq!(sum, 6);
1128 });
1129 }
1130
1131 #[test]
1132 fn test_iter_try_fold() {
1133 Python::with_gil(|py: Python<'_>| {
1134 let list = PyList::new(py, [1, 2, 3]).unwrap();
1135 let sum = list
1136 .iter()
1137 .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1138 .unwrap();
1139 assert_eq!(sum, 6);
1140
1141 let list = PyList::new(py, ["foo", "bar"]).unwrap();
1142 assert!(list
1143 .iter()
1144 .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1145 .is_err());
1146 });
1147 }
1148
1149 #[test]
1150 fn test_iter_try_rfold() {
1151 Python::with_gil(|py: Python<'_>| {
1152 let list = PyList::new(py, [1, 2, 3]).unwrap();
1153 let sum = list
1154 .iter()
1155 .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1156 .unwrap();
1157 assert_eq!(sum, 6);
1158
1159 let list = PyList::new(py, ["foo", "bar"]).unwrap();
1160 assert!(list
1161 .iter()
1162 .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1163 .is_err());
1164 });
1165 }
1166
1167 #[test]
1168 fn test_into_iter() {
1169 Python::with_gil(|py| {
1170 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1171 for (i, item) in list.iter().enumerate() {
1172 assert_eq!((i + 1) as i32, item.extract::<i32>().unwrap());
1173 }
1174 });
1175 }
1176
1177 #[test]
1178 fn test_into_iter_bound() {
1179 use crate::types::any::PyAnyMethods;
1180
1181 Python::with_gil(|py| {
1182 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1183 let mut items = vec![];
1184 for item in &list {
1185 items.push(item.extract::<i32>().unwrap());
1186 }
1187 assert_eq!(items, vec![1, 2, 3, 4]);
1188 });
1189 }
1190
1191 #[test]
1192 fn test_as_sequence() {
1193 Python::with_gil(|py| {
1194 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1195
1196 assert_eq!(list.as_sequence().len().unwrap(), 4);
1197 assert_eq!(
1198 list.as_sequence()
1199 .get_item(1)
1200 .unwrap()
1201 .extract::<i32>()
1202 .unwrap(),
1203 2
1204 );
1205 });
1206 }
1207
1208 #[test]
1209 fn test_into_sequence() {
1210 Python::with_gil(|py| {
1211 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1212
1213 let sequence = list.into_sequence();
1214
1215 assert_eq!(sequence.len().unwrap(), 4);
1216 assert_eq!(sequence.get_item(1).unwrap().extract::<i32>().unwrap(), 2);
1217 });
1218 }
1219
1220 #[test]
1221 fn test_extract() {
1222 Python::with_gil(|py| {
1223 let v = vec![2, 3, 5, 7];
1224 let list = PyList::new(py, &v).unwrap();
1225 let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
1226 assert_eq!(v, v2);
1227 });
1228 }
1229
1230 #[test]
1231 fn test_sort() {
1232 Python::with_gil(|py| {
1233 let v = vec![7, 3, 2, 5];
1234 let list = PyList::new(py, &v).unwrap();
1235 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1236 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1237 assert_eq!(2, list.get_item(2).unwrap().extract::<i32>().unwrap());
1238 assert_eq!(5, list.get_item(3).unwrap().extract::<i32>().unwrap());
1239 list.sort().unwrap();
1240 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1241 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1242 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1243 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1244 });
1245 }
1246
1247 #[test]
1248 fn test_reverse() {
1249 Python::with_gil(|py| {
1250 let v = vec![2, 3, 5, 7];
1251 let list = PyList::new(py, &v).unwrap();
1252 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1253 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1254 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1255 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1256 list.reverse().unwrap();
1257 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1258 assert_eq!(5, list.get_item(1).unwrap().extract::<i32>().unwrap());
1259 assert_eq!(3, list.get_item(2).unwrap().extract::<i32>().unwrap());
1260 assert_eq!(2, list.get_item(3).unwrap().extract::<i32>().unwrap());
1261 });
1262 }
1263
1264 #[test]
1265 fn test_array_into_pyobject() {
1266 Python::with_gil(|py| {
1267 let array = [1, 2].into_pyobject(py).unwrap();
1268 let list = array.downcast::<PyList>().unwrap();
1269 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1270 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
1271 });
1272 }
1273
1274 #[test]
1275 fn test_list_get_item_invalid_index() {
1276 Python::with_gil(|py| {
1277 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1278 let obj = list.get_item(5);
1279 assert!(obj.is_err());
1280 assert_eq!(
1281 obj.unwrap_err().to_string(),
1282 "IndexError: list index out of range"
1283 );
1284 });
1285 }
1286
1287 #[test]
1288 fn test_list_get_item_sanity() {
1289 Python::with_gil(|py| {
1290 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1291 let obj = list.get_item(0);
1292 assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
1293 });
1294 }
1295
1296 #[cfg(not(Py_LIMITED_API))]
1297 #[test]
1298 fn test_list_get_item_unchecked_sanity() {
1299 Python::with_gil(|py| {
1300 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1301 let obj = unsafe { list.get_item_unchecked(0) };
1302 assert_eq!(obj.extract::<i32>().unwrap(), 2);
1303 });
1304 }
1305
1306 #[test]
1307 fn test_list_del_item() {
1308 Python::with_gil(|py| {
1309 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1310 assert!(list.del_item(10).is_err());
1311 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1312 assert!(list.del_item(0).is_ok());
1313 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1314 assert!(list.del_item(0).is_ok());
1315 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1316 assert!(list.del_item(0).is_ok());
1317 assert_eq!(3, list.get_item(0).unwrap().extract::<i32>().unwrap());
1318 assert!(list.del_item(0).is_ok());
1319 assert_eq!(5, list.get_item(0).unwrap().extract::<i32>().unwrap());
1320 assert!(list.del_item(0).is_ok());
1321 assert_eq!(8, list.get_item(0).unwrap().extract::<i32>().unwrap());
1322 assert!(list.del_item(0).is_ok());
1323 assert_eq!(0, list.len());
1324 assert!(list.del_item(0).is_err());
1325 });
1326 }
1327
1328 #[test]
1329 fn test_list_set_slice() {
1330 Python::with_gil(|py| {
1331 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1332 let ins = PyList::new(py, [7, 4]).unwrap();
1333 list.set_slice(1, 4, &ins).unwrap();
1334 assert_eq!([1, 7, 4, 5, 8], list.extract::<[i32; 5]>().unwrap());
1335 list.set_slice(3, 100, &PyList::empty(py)).unwrap();
1336 assert_eq!([1, 7, 4], list.extract::<[i32; 3]>().unwrap());
1337 });
1338 }
1339
1340 #[test]
1341 fn test_list_del_slice() {
1342 Python::with_gil(|py| {
1343 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1344 list.del_slice(1, 4).unwrap();
1345 assert_eq!([1, 5, 8], list.extract::<[i32; 3]>().unwrap());
1346 list.del_slice(1, 100).unwrap();
1347 assert_eq!([1], list.extract::<[i32; 1]>().unwrap());
1348 });
1349 }
1350
1351 #[test]
1352 fn test_list_contains() {
1353 Python::with_gil(|py| {
1354 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1355 assert_eq!(6, list.len());
1356
1357 let bad_needle = 7i32.into_pyobject(py).unwrap();
1358 assert!(!list.contains(&bad_needle).unwrap());
1359
1360 let good_needle = 8i32.into_pyobject(py).unwrap();
1361 assert!(list.contains(&good_needle).unwrap());
1362
1363 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1364 assert!(list.contains(&type_coerced_needle).unwrap());
1365 });
1366 }
1367
1368 #[test]
1369 fn test_list_index() {
1370 Python::with_gil(|py| {
1371 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1372 assert_eq!(0, list.index(1i32).unwrap());
1373 assert_eq!(2, list.index(2i32).unwrap());
1374 assert_eq!(3, list.index(3i32).unwrap());
1375 assert_eq!(4, list.index(5i32).unwrap());
1376 assert_eq!(5, list.index(8i32).unwrap());
1377 assert!(list.index(42i32).is_err());
1378 });
1379 }
1380
1381 use std::ops::Range;
1382
1383 struct FaultyIter(Range<usize>, usize);
1386
1387 impl Iterator for FaultyIter {
1388 type Item = usize;
1389
1390 fn next(&mut self) -> Option<Self::Item> {
1391 self.0.next()
1392 }
1393 }
1394
1395 impl ExactSizeIterator for FaultyIter {
1396 fn len(&self) -> usize {
1397 self.1
1398 }
1399 }
1400
1401 #[test]
1402 #[should_panic(
1403 expected = "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation."
1404 )]
1405 fn too_long_iterator() {
1406 Python::with_gil(|py| {
1407 let iter = FaultyIter(0..usize::MAX, 73);
1408 let _list = PyList::new(py, iter).unwrap();
1409 })
1410 }
1411
1412 #[test]
1413 #[should_panic(
1414 expected = "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation."
1415 )]
1416 fn too_short_iterator() {
1417 Python::with_gil(|py| {
1418 let iter = FaultyIter(0..35, 73);
1419 let _list = PyList::new(py, iter).unwrap();
1420 })
1421 }
1422
1423 #[test]
1424 #[should_panic(
1425 expected = "out of range integral type conversion attempted on `elements.len()`"
1426 )]
1427 fn overflowing_size() {
1428 Python::with_gil(|py| {
1429 let iter = FaultyIter(0..0, usize::MAX);
1430
1431 let _list = PyList::new(py, iter).unwrap();
1432 })
1433 }
1434
1435 #[test]
1436 fn bad_intopyobject_doesnt_cause_leaks() {
1437 use crate::types::PyInt;
1438 use std::convert::Infallible;
1439 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1440 static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0);
1441
1442 struct Bad(usize);
1443
1444 impl Drop for Bad {
1445 fn drop(&mut self) {
1446 NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst);
1447 }
1448 }
1449
1450 impl<'py> IntoPyObject<'py> for Bad {
1451 type Target = PyInt;
1452 type Output = crate::Bound<'py, Self::Target>;
1453 type Error = Infallible;
1454
1455 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
1456 assert_ne!(self.0, 42);
1458 self.0.into_pyobject(py)
1459 }
1460 }
1461
1462 struct FaultyIter(Range<usize>, usize);
1463
1464 impl Iterator for FaultyIter {
1465 type Item = Bad;
1466
1467 fn next(&mut self) -> Option<Self::Item> {
1468 self.0.next().map(|i| {
1469 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
1470 Bad(i)
1471 })
1472 }
1473 }
1474
1475 impl ExactSizeIterator for FaultyIter {
1476 fn len(&self) -> usize {
1477 self.1
1478 }
1479 }
1480
1481 Python::with_gil(|py| {
1482 std::panic::catch_unwind(|| {
1483 let iter = FaultyIter(0..50, 50);
1484 let _list = PyList::new(py, iter).unwrap();
1485 })
1486 .unwrap_err();
1487 });
1488
1489 assert_eq!(
1490 NEEDS_DESTRUCTING_COUNT.load(SeqCst),
1491 0,
1492 "Some destructors did not run"
1493 );
1494 }
1495
1496 #[test]
1497 fn test_list_to_tuple() {
1498 Python::with_gil(|py| {
1499 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1500 let tuple = list.to_tuple();
1501 let tuple_expected = PyTuple::new(py, vec![1, 2, 3]).unwrap();
1502 assert!(tuple.eq(tuple_expected).unwrap());
1503 })
1504 }
1505}