1use crate::err::{self, PyResult};
2use crate::ffi::{self, Py_ssize_t};
3use crate::ffi_ptr_ext::FfiPtrExt;
4use crate::internal_tricks::get_ssize_index;
5use crate::types::any::PyAnyMethods;
6use crate::types::sequence::PySequenceMethods;
7use crate::types::{PySequence, PyTuple};
8use crate::{
9 Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr, PyObject, Python,
10};
11use std::iter::FusedIterator;
12#[cfg(feature = "nightly")]
13use std::num::NonZero;
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]
551 #[cfg(not(feature = "nightly"))]
552 fn nth(
553 index: &mut Index,
554 length: &mut Length,
555 list: &Bound<'py, PyList>,
556 n: usize,
557 ) -> Option<Bound<'py, PyAny>> {
558 let length = length.0.min(list.len());
559 let target_index = index.0 + n;
560 if target_index < length {
561 let item = {
562 #[cfg(Py_LIMITED_API)]
563 {
564 list.get_item(target_index).expect("get-item failed")
565 }
566
567 #[cfg(not(Py_LIMITED_API))]
568 {
569 unsafe { list.get_item_unchecked(target_index) }
570 }
571 };
572 index.0 = target_index + 1;
573 Some(item)
574 } else {
575 None
576 }
577 }
578
579 #[inline]
585 #[cfg(not(Py_LIMITED_API))]
586 #[deny(unsafe_op_in_unsafe_fn)]
587 unsafe fn next_back_unchecked(
588 index: &mut Index,
589 length: &mut Length,
590 list: &Bound<'py, PyList>,
591 ) -> Option<Bound<'py, PyAny>> {
592 let current_length = length.0.min(list.len());
593
594 if index.0 < current_length {
595 let item = unsafe { list.get_item_unchecked(current_length - 1) };
596 length.0 = current_length - 1;
597 Some(item)
598 } else {
599 None
600 }
601 }
602
603 #[inline]
604 #[cfg(Py_LIMITED_API)]
605 fn next_back(
606 index: &mut Index,
607 length: &mut Length,
608 list: &Bound<'py, PyList>,
609 ) -> Option<Bound<'py, PyAny>> {
610 let current_length = (length.0).min(list.len());
611
612 if index.0 < current_length {
613 let item = list.get_item(current_length - 1).expect("get-item failed");
614 length.0 = current_length - 1;
615 Some(item)
616 } else {
617 None
618 }
619 }
620
621 #[inline]
622 #[cfg(not(feature = "nightly"))]
623 fn nth_back(
624 index: &mut Index,
625 length: &mut Length,
626 list: &Bound<'py, PyList>,
627 n: usize,
628 ) -> Option<Bound<'py, PyAny>> {
629 let length_size = length.0.min(list.len());
630 if index.0 + n < length_size {
631 let target_index = length_size - n - 1;
632 let item = {
633 #[cfg(not(Py_LIMITED_API))]
634 {
635 unsafe { list.get_item_unchecked(target_index) }
636 }
637
638 #[cfg(Py_LIMITED_API)]
639 {
640 list.get_item(target_index).expect("get-item failed")
641 }
642 };
643 length.0 = target_index;
644 Some(item)
645 } else {
646 None
647 }
648 }
649
650 #[allow(dead_code)]
651 fn with_critical_section<R>(
652 &mut self,
653 f: impl FnOnce(&mut Index, &mut Length, &Bound<'py, PyList>) -> R,
654 ) -> R {
655 let Self {
656 index,
657 length,
658 list,
659 } = self;
660 crate::sync::with_critical_section(list, || f(index, length, list))
661 }
662}
663
664impl<'py> Iterator for BoundListIterator<'py> {
665 type Item = Bound<'py, PyAny>;
666
667 #[inline]
668 fn next(&mut self) -> Option<Self::Item> {
669 #[cfg(not(Py_LIMITED_API))]
670 {
671 self.with_critical_section(|index, length, list| unsafe {
672 Self::next_unchecked(index, length, list)
673 })
674 }
675 #[cfg(Py_LIMITED_API)]
676 {
677 let Self {
678 index,
679 length,
680 list,
681 } = self;
682 Self::next(index, length, list)
683 }
684 }
685
686 #[inline]
687 #[cfg(not(feature = "nightly"))]
688 fn nth(&mut self, n: usize) -> Option<Self::Item> {
689 self.with_critical_section(|index, length, list| Self::nth(index, length, list, n))
690 }
691
692 #[inline]
693 fn size_hint(&self) -> (usize, Option<usize>) {
694 let len = self.len();
695 (len, Some(len))
696 }
697
698 #[inline]
699 fn count(self) -> usize
700 where
701 Self: Sized,
702 {
703 self.len()
704 }
705
706 #[inline]
707 fn last(mut self) -> Option<Self::Item>
708 where
709 Self: Sized,
710 {
711 self.next_back()
712 }
713
714 #[inline]
715 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
716 fn fold<B, F>(mut self, init: B, mut f: F) -> B
717 where
718 Self: Sized,
719 F: FnMut(B, Self::Item) -> B,
720 {
721 self.with_critical_section(|index, length, list| {
722 let mut accum = init;
723 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
724 accum = f(accum, x);
725 }
726 accum
727 })
728 }
729
730 #[inline]
731 #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
732 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
733 where
734 Self: Sized,
735 F: FnMut(B, Self::Item) -> R,
736 R: std::ops::Try<Output = B>,
737 {
738 self.with_critical_section(|index, length, list| {
739 let mut accum = init;
740 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
741 accum = f(accum, x)?
742 }
743 R::from_output(accum)
744 })
745 }
746
747 #[inline]
748 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
749 fn all<F>(&mut self, mut f: F) -> bool
750 where
751 Self: Sized,
752 F: FnMut(Self::Item) -> bool,
753 {
754 self.with_critical_section(|index, length, list| {
755 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
756 if !f(x) {
757 return false;
758 }
759 }
760 true
761 })
762 }
763
764 #[inline]
765 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
766 fn any<F>(&mut self, mut f: F) -> bool
767 where
768 Self: Sized,
769 F: FnMut(Self::Item) -> bool,
770 {
771 self.with_critical_section(|index, length, list| {
772 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
773 if f(x) {
774 return true;
775 }
776 }
777 false
778 })
779 }
780
781 #[inline]
782 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
783 fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
784 where
785 Self: Sized,
786 P: FnMut(&Self::Item) -> bool,
787 {
788 self.with_critical_section(|index, length, list| {
789 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
790 if predicate(&x) {
791 return Some(x);
792 }
793 }
794 None
795 })
796 }
797
798 #[inline]
799 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
800 fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
801 where
802 Self: Sized,
803 F: FnMut(Self::Item) -> Option<B>,
804 {
805 self.with_critical_section(|index, length, list| {
806 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
807 if let found @ Some(_) = f(x) {
808 return found;
809 }
810 }
811 None
812 })
813 }
814
815 #[inline]
816 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
817 fn position<P>(&mut self, mut predicate: P) -> Option<usize>
818 where
819 Self: Sized,
820 P: FnMut(Self::Item) -> bool,
821 {
822 self.with_critical_section(|index, length, list| {
823 let mut acc = 0;
824 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
825 if predicate(x) {
826 return Some(acc);
827 }
828 acc += 1;
829 }
830 None
831 })
832 }
833
834 #[inline]
835 #[cfg(feature = "nightly")]
836 fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
837 self.with_critical_section(|index, length, list| {
838 let max_len = length.0.min(list.len());
839 let currently_at = index.0;
840 if currently_at >= max_len {
841 if n == 0 {
842 return Ok(());
843 } else {
844 return Err(unsafe { NonZero::new_unchecked(n) });
845 }
846 }
847
848 let items_left = max_len - currently_at;
849 if n <= items_left {
850 index.0 += n;
851 Ok(())
852 } else {
853 index.0 = max_len;
854 let remainder = n - items_left;
855 Err(unsafe { NonZero::new_unchecked(remainder) })
856 }
857 })
858 }
859}
860
861impl DoubleEndedIterator for BoundListIterator<'_> {
862 #[inline]
863 fn next_back(&mut self) -> Option<Self::Item> {
864 #[cfg(not(Py_LIMITED_API))]
865 {
866 self.with_critical_section(|index, length, list| unsafe {
867 Self::next_back_unchecked(index, length, list)
868 })
869 }
870 #[cfg(Py_LIMITED_API)]
871 {
872 let Self {
873 index,
874 length,
875 list,
876 } = self;
877 Self::next_back(index, length, list)
878 }
879 }
880
881 #[inline]
882 #[cfg(not(feature = "nightly"))]
883 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
884 self.with_critical_section(|index, length, list| Self::nth_back(index, length, list, n))
885 }
886
887 #[inline]
888 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
889 fn rfold<B, F>(mut self, init: B, mut f: F) -> B
890 where
891 Self: Sized,
892 F: FnMut(B, Self::Item) -> B,
893 {
894 self.with_critical_section(|index, length, list| {
895 let mut accum = init;
896 while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
897 accum = f(accum, x);
898 }
899 accum
900 })
901 }
902
903 #[inline]
904 #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
905 fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
906 where
907 Self: Sized,
908 F: FnMut(B, Self::Item) -> R,
909 R: std::ops::Try<Output = B>,
910 {
911 self.with_critical_section(|index, length, list| {
912 let mut accum = init;
913 while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
914 accum = f(accum, x)?
915 }
916 R::from_output(accum)
917 })
918 }
919
920 #[inline]
921 #[cfg(feature = "nightly")]
922 fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
923 self.with_critical_section(|index, length, list| {
924 let max_len = length.0.min(list.len());
925 let currently_at = index.0;
926 if currently_at >= max_len {
927 if n == 0 {
928 return Ok(());
929 } else {
930 return Err(unsafe { NonZero::new_unchecked(n) });
931 }
932 }
933
934 let items_left = max_len - currently_at;
935 if n <= items_left {
936 length.0 = max_len - n;
937 Ok(())
938 } else {
939 length.0 = currently_at;
940 let remainder = n - items_left;
941 Err(unsafe { NonZero::new_unchecked(remainder) })
942 }
943 })
944 }
945}
946
947impl ExactSizeIterator for BoundListIterator<'_> {
948 fn len(&self) -> usize {
949 self.length.0.saturating_sub(self.index.0)
950 }
951}
952
953impl FusedIterator for BoundListIterator<'_> {}
954
955impl<'py> IntoIterator for Bound<'py, PyList> {
956 type Item = Bound<'py, PyAny>;
957 type IntoIter = BoundListIterator<'py>;
958
959 fn into_iter(self) -> Self::IntoIter {
960 BoundListIterator::new(self)
961 }
962}
963
964impl<'py> IntoIterator for &Bound<'py, PyList> {
965 type Item = Bound<'py, PyAny>;
966 type IntoIter = BoundListIterator<'py>;
967
968 fn into_iter(self) -> Self::IntoIter {
969 self.iter()
970 }
971}
972
973#[cfg(test)]
974mod tests {
975 use crate::types::any::PyAnyMethods;
976 use crate::types::list::PyListMethods;
977 use crate::types::sequence::PySequenceMethods;
978 use crate::types::{PyList, PyTuple};
979 use crate::{ffi, IntoPyObject, PyResult, Python};
980 #[cfg(feature = "nightly")]
981 use std::num::NonZero;
982
983 #[test]
984 fn test_new() {
985 Python::with_gil(|py| {
986 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
987 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
988 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
989 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
990 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
991 });
992 }
993
994 #[test]
995 fn test_len() {
996 Python::with_gil(|py| {
997 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
998 assert_eq!(4, list.len());
999 });
1000 }
1001
1002 #[test]
1003 fn test_get_item() {
1004 Python::with_gil(|py| {
1005 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1006 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1007 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1008 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1009 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1010 });
1011 }
1012
1013 #[test]
1014 fn test_get_slice() {
1015 Python::with_gil(|py| {
1016 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1017 let slice = list.get_slice(1, 3);
1018 assert_eq!(2, slice.len());
1019 let slice = list.get_slice(1, 7);
1020 assert_eq!(3, slice.len());
1021 });
1022 }
1023
1024 #[test]
1025 fn test_set_item() {
1026 Python::with_gil(|py| {
1027 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1028 let val = 42i32.into_pyobject(py).unwrap();
1029 let val2 = 42i32.into_pyobject(py).unwrap();
1030 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1031 list.set_item(0, val).unwrap();
1032 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
1033 assert!(list.set_item(10, val2).is_err());
1034 });
1035 }
1036
1037 #[test]
1038 fn test_set_item_refcnt() {
1039 Python::with_gil(|py| {
1040 let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
1041 let cnt;
1042 {
1043 let v = vec![2];
1044 let ob = v.into_pyobject(py).unwrap();
1045 let list = ob.downcast::<PyList>().unwrap();
1046 cnt = obj.get_refcnt();
1047 list.set_item(0, &obj).unwrap();
1048 }
1049
1050 assert_eq!(cnt, obj.get_refcnt());
1051 });
1052 }
1053
1054 #[test]
1055 fn test_insert() {
1056 Python::with_gil(|py| {
1057 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1058 let val = 42i32.into_pyobject(py).unwrap();
1059 let val2 = 43i32.into_pyobject(py).unwrap();
1060 assert_eq!(4, list.len());
1061 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1062 list.insert(0, val).unwrap();
1063 list.insert(1000, val2).unwrap();
1064 assert_eq!(6, list.len());
1065 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
1066 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
1067 assert_eq!(43, list.get_item(5).unwrap().extract::<i32>().unwrap());
1068 });
1069 }
1070
1071 #[test]
1072 fn test_insert_refcnt() {
1073 Python::with_gil(|py| {
1074 let cnt;
1075 let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
1076 {
1077 let list = PyList::empty(py);
1078 cnt = obj.get_refcnt();
1079 list.insert(0, &obj).unwrap();
1080 }
1081
1082 assert_eq!(cnt, obj.get_refcnt());
1083 });
1084 }
1085
1086 #[test]
1087 fn test_append() {
1088 Python::with_gil(|py| {
1089 let list = PyList::new(py, [2]).unwrap();
1090 list.append(3).unwrap();
1091 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1092 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1093 });
1094 }
1095
1096 #[test]
1097 fn test_append_refcnt() {
1098 Python::with_gil(|py| {
1099 let cnt;
1100 let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
1101 {
1102 let list = PyList::empty(py);
1103 cnt = obj.get_refcnt();
1104 list.append(&obj).unwrap();
1105 }
1106 assert_eq!(cnt, obj.get_refcnt());
1107 });
1108 }
1109
1110 #[test]
1111 fn test_iter() {
1112 Python::with_gil(|py| {
1113 let v = vec![2, 3, 5, 7];
1114 let list = PyList::new(py, &v).unwrap();
1115 let mut idx = 0;
1116 for el in list {
1117 assert_eq!(v[idx], el.extract::<i32>().unwrap());
1118 idx += 1;
1119 }
1120 assert_eq!(idx, v.len());
1121 });
1122 }
1123
1124 #[test]
1125 fn test_iter_size_hint() {
1126 Python::with_gil(|py| {
1127 let v = vec![2, 3, 5, 7];
1128 let ob = (&v).into_pyobject(py).unwrap();
1129 let list = ob.downcast::<PyList>().unwrap();
1130
1131 let mut iter = list.iter();
1132 assert_eq!(iter.size_hint(), (v.len(), Some(v.len())));
1133 iter.next();
1134 assert_eq!(iter.size_hint(), (v.len() - 1, Some(v.len() - 1)));
1135
1136 for _ in &mut iter {}
1138
1139 assert_eq!(iter.size_hint(), (0, Some(0)));
1140 });
1141 }
1142
1143 #[test]
1144 fn test_iter_rev() {
1145 Python::with_gil(|py| {
1146 let v = vec![2, 3, 5, 7];
1147 let ob = v.into_pyobject(py).unwrap();
1148 let list = ob.downcast::<PyList>().unwrap();
1149
1150 let mut iter = list.iter().rev();
1151
1152 assert_eq!(iter.size_hint(), (4, Some(4)));
1153
1154 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 7);
1155 assert_eq!(iter.size_hint(), (3, Some(3)));
1156
1157 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 5);
1158 assert_eq!(iter.size_hint(), (2, Some(2)));
1159
1160 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
1161 assert_eq!(iter.size_hint(), (1, Some(1)));
1162
1163 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 2);
1164 assert_eq!(iter.size_hint(), (0, Some(0)));
1165
1166 assert!(iter.next().is_none());
1167 assert!(iter.next().is_none());
1168 });
1169 }
1170
1171 #[test]
1172 fn test_iter_all() {
1173 Python::with_gil(|py| {
1174 let list = PyList::new(py, [true, true, true]).unwrap();
1175 assert!(list.iter().all(|x| x.extract::<bool>().unwrap()));
1176
1177 let list = PyList::new(py, [true, false, true]).unwrap();
1178 assert!(!list.iter().all(|x| x.extract::<bool>().unwrap()));
1179 });
1180 }
1181
1182 #[test]
1183 fn test_iter_any() {
1184 Python::with_gil(|py| {
1185 let list = PyList::new(py, [true, true, true]).unwrap();
1186 assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1187
1188 let list = PyList::new(py, [true, false, true]).unwrap();
1189 assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1190
1191 let list = PyList::new(py, [false, false, false]).unwrap();
1192 assert!(!list.iter().any(|x| x.extract::<bool>().unwrap()));
1193 });
1194 }
1195
1196 #[test]
1197 fn test_iter_find() {
1198 Python::with_gil(|py: Python<'_>| {
1199 let list = PyList::new(py, ["hello", "world"]).unwrap();
1200 assert_eq!(
1201 Some("world".to_string()),
1202 list.iter()
1203 .find(|v| v.extract::<String>().unwrap() == "world")
1204 .map(|v| v.extract::<String>().unwrap())
1205 );
1206 assert_eq!(
1207 None,
1208 list.iter()
1209 .find(|v| v.extract::<String>().unwrap() == "foobar")
1210 .map(|v| v.extract::<String>().unwrap())
1211 );
1212 });
1213 }
1214
1215 #[test]
1216 fn test_iter_position() {
1217 Python::with_gil(|py: Python<'_>| {
1218 let list = PyList::new(py, ["hello", "world"]).unwrap();
1219 assert_eq!(
1220 Some(1),
1221 list.iter()
1222 .position(|v| v.extract::<String>().unwrap() == "world")
1223 );
1224 assert_eq!(
1225 None,
1226 list.iter()
1227 .position(|v| v.extract::<String>().unwrap() == "foobar")
1228 );
1229 });
1230 }
1231
1232 #[test]
1233 fn test_iter_fold() {
1234 Python::with_gil(|py: Python<'_>| {
1235 let list = PyList::new(py, [1, 2, 3]).unwrap();
1236 let sum = list
1237 .iter()
1238 .fold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1239 assert_eq!(sum, 6);
1240 });
1241 }
1242
1243 #[test]
1244 fn test_iter_fold_out_of_bounds() {
1245 Python::with_gil(|py: Python<'_>| {
1246 let list = PyList::new(py, [1, 2, 3]).unwrap();
1247 let sum = list.iter().fold(0, |_, _| {
1248 for _ in 0..3 {
1251 list.del_item(0).unwrap();
1252 }
1253 -5
1254 });
1255 assert_eq!(sum, -5);
1256 assert!(list.len() == 0);
1257 });
1258 }
1259
1260 #[test]
1261 fn test_iter_rfold() {
1262 Python::with_gil(|py: Python<'_>| {
1263 let list = PyList::new(py, [1, 2, 3]).unwrap();
1264 let sum = list
1265 .iter()
1266 .rfold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1267 assert_eq!(sum, 6);
1268 });
1269 }
1270
1271 #[test]
1272 fn test_iter_try_fold() {
1273 Python::with_gil(|py: Python<'_>| {
1274 let list = PyList::new(py, [1, 2, 3]).unwrap();
1275 let sum = list
1276 .iter()
1277 .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1278 .unwrap();
1279 assert_eq!(sum, 6);
1280
1281 let list = PyList::new(py, ["foo", "bar"]).unwrap();
1282 assert!(list
1283 .iter()
1284 .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1285 .is_err());
1286 });
1287 }
1288
1289 #[test]
1290 fn test_iter_try_rfold() {
1291 Python::with_gil(|py: Python<'_>| {
1292 let list = PyList::new(py, [1, 2, 3]).unwrap();
1293 let sum = list
1294 .iter()
1295 .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1296 .unwrap();
1297 assert_eq!(sum, 6);
1298
1299 let list = PyList::new(py, ["foo", "bar"]).unwrap();
1300 assert!(list
1301 .iter()
1302 .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1303 .is_err());
1304 });
1305 }
1306
1307 #[test]
1308 fn test_into_iter() {
1309 Python::with_gil(|py| {
1310 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1311 for (i, item) in list.iter().enumerate() {
1312 assert_eq!((i + 1) as i32, item.extract::<i32>().unwrap());
1313 }
1314 });
1315 }
1316
1317 #[test]
1318 fn test_into_iter_bound() {
1319 use crate::types::any::PyAnyMethods;
1320
1321 Python::with_gil(|py| {
1322 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1323 let mut items = vec![];
1324 for item in &list {
1325 items.push(item.extract::<i32>().unwrap());
1326 }
1327 assert_eq!(items, vec![1, 2, 3, 4]);
1328 });
1329 }
1330
1331 #[test]
1332 fn test_as_sequence() {
1333 Python::with_gil(|py| {
1334 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1335
1336 assert_eq!(list.as_sequence().len().unwrap(), 4);
1337 assert_eq!(
1338 list.as_sequence()
1339 .get_item(1)
1340 .unwrap()
1341 .extract::<i32>()
1342 .unwrap(),
1343 2
1344 );
1345 });
1346 }
1347
1348 #[test]
1349 fn test_into_sequence() {
1350 Python::with_gil(|py| {
1351 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1352
1353 let sequence = list.into_sequence();
1354
1355 assert_eq!(sequence.len().unwrap(), 4);
1356 assert_eq!(sequence.get_item(1).unwrap().extract::<i32>().unwrap(), 2);
1357 });
1358 }
1359
1360 #[test]
1361 fn test_extract() {
1362 Python::with_gil(|py| {
1363 let v = vec![2, 3, 5, 7];
1364 let list = PyList::new(py, &v).unwrap();
1365 let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
1366 assert_eq!(v, v2);
1367 });
1368 }
1369
1370 #[test]
1371 fn test_sort() {
1372 Python::with_gil(|py| {
1373 let v = vec![7, 3, 2, 5];
1374 let list = PyList::new(py, &v).unwrap();
1375 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1376 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1377 assert_eq!(2, list.get_item(2).unwrap().extract::<i32>().unwrap());
1378 assert_eq!(5, list.get_item(3).unwrap().extract::<i32>().unwrap());
1379 list.sort().unwrap();
1380 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1381 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1382 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1383 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1384 });
1385 }
1386
1387 #[test]
1388 fn test_reverse() {
1389 Python::with_gil(|py| {
1390 let v = vec![2, 3, 5, 7];
1391 let list = PyList::new(py, &v).unwrap();
1392 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1393 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1394 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1395 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1396 list.reverse().unwrap();
1397 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1398 assert_eq!(5, list.get_item(1).unwrap().extract::<i32>().unwrap());
1399 assert_eq!(3, list.get_item(2).unwrap().extract::<i32>().unwrap());
1400 assert_eq!(2, list.get_item(3).unwrap().extract::<i32>().unwrap());
1401 });
1402 }
1403
1404 #[test]
1405 fn test_array_into_pyobject() {
1406 Python::with_gil(|py| {
1407 let array = [1, 2].into_pyobject(py).unwrap();
1408 let list = array.downcast::<PyList>().unwrap();
1409 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1410 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
1411 });
1412 }
1413
1414 #[test]
1415 fn test_list_get_item_invalid_index() {
1416 Python::with_gil(|py| {
1417 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1418 let obj = list.get_item(5);
1419 assert!(obj.is_err());
1420 assert_eq!(
1421 obj.unwrap_err().to_string(),
1422 "IndexError: list index out of range"
1423 );
1424 });
1425 }
1426
1427 #[test]
1428 fn test_list_get_item_sanity() {
1429 Python::with_gil(|py| {
1430 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1431 let obj = list.get_item(0);
1432 assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
1433 });
1434 }
1435
1436 #[cfg(not(Py_LIMITED_API))]
1437 #[test]
1438 fn test_list_get_item_unchecked_sanity() {
1439 Python::with_gil(|py| {
1440 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1441 let obj = unsafe { list.get_item_unchecked(0) };
1442 assert_eq!(obj.extract::<i32>().unwrap(), 2);
1443 });
1444 }
1445
1446 #[test]
1447 fn test_list_del_item() {
1448 Python::with_gil(|py| {
1449 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1450 assert!(list.del_item(10).is_err());
1451 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1452 assert!(list.del_item(0).is_ok());
1453 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1454 assert!(list.del_item(0).is_ok());
1455 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1456 assert!(list.del_item(0).is_ok());
1457 assert_eq!(3, list.get_item(0).unwrap().extract::<i32>().unwrap());
1458 assert!(list.del_item(0).is_ok());
1459 assert_eq!(5, list.get_item(0).unwrap().extract::<i32>().unwrap());
1460 assert!(list.del_item(0).is_ok());
1461 assert_eq!(8, list.get_item(0).unwrap().extract::<i32>().unwrap());
1462 assert!(list.del_item(0).is_ok());
1463 assert_eq!(0, list.len());
1464 assert!(list.del_item(0).is_err());
1465 });
1466 }
1467
1468 #[test]
1469 fn test_list_set_slice() {
1470 Python::with_gil(|py| {
1471 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1472 let ins = PyList::new(py, [7, 4]).unwrap();
1473 list.set_slice(1, 4, &ins).unwrap();
1474 assert_eq!([1, 7, 4, 5, 8], list.extract::<[i32; 5]>().unwrap());
1475 list.set_slice(3, 100, &PyList::empty(py)).unwrap();
1476 assert_eq!([1, 7, 4], list.extract::<[i32; 3]>().unwrap());
1477 });
1478 }
1479
1480 #[test]
1481 fn test_list_del_slice() {
1482 Python::with_gil(|py| {
1483 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1484 list.del_slice(1, 4).unwrap();
1485 assert_eq!([1, 5, 8], list.extract::<[i32; 3]>().unwrap());
1486 list.del_slice(1, 100).unwrap();
1487 assert_eq!([1], list.extract::<[i32; 1]>().unwrap());
1488 });
1489 }
1490
1491 #[test]
1492 fn test_list_contains() {
1493 Python::with_gil(|py| {
1494 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1495 assert_eq!(6, list.len());
1496
1497 let bad_needle = 7i32.into_pyobject(py).unwrap();
1498 assert!(!list.contains(&bad_needle).unwrap());
1499
1500 let good_needle = 8i32.into_pyobject(py).unwrap();
1501 assert!(list.contains(&good_needle).unwrap());
1502
1503 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1504 assert!(list.contains(&type_coerced_needle).unwrap());
1505 });
1506 }
1507
1508 #[test]
1509 fn test_list_index() {
1510 Python::with_gil(|py| {
1511 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1512 assert_eq!(0, list.index(1i32).unwrap());
1513 assert_eq!(2, list.index(2i32).unwrap());
1514 assert_eq!(3, list.index(3i32).unwrap());
1515 assert_eq!(4, list.index(5i32).unwrap());
1516 assert_eq!(5, list.index(8i32).unwrap());
1517 assert!(list.index(42i32).is_err());
1518 });
1519 }
1520
1521 use std::ops::Range;
1522
1523 struct FaultyIter(Range<usize>, usize);
1526
1527 impl Iterator for FaultyIter {
1528 type Item = usize;
1529
1530 fn next(&mut self) -> Option<Self::Item> {
1531 self.0.next()
1532 }
1533 }
1534
1535 impl ExactSizeIterator for FaultyIter {
1536 fn len(&self) -> usize {
1537 self.1
1538 }
1539 }
1540
1541 #[test]
1542 #[should_panic(
1543 expected = "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation."
1544 )]
1545 fn too_long_iterator() {
1546 Python::with_gil(|py| {
1547 let iter = FaultyIter(0..usize::MAX, 73);
1548 let _list = PyList::new(py, iter).unwrap();
1549 })
1550 }
1551
1552 #[test]
1553 #[should_panic(
1554 expected = "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation."
1555 )]
1556 fn too_short_iterator() {
1557 Python::with_gil(|py| {
1558 let iter = FaultyIter(0..35, 73);
1559 let _list = PyList::new(py, iter).unwrap();
1560 })
1561 }
1562
1563 #[test]
1564 #[should_panic(
1565 expected = "out of range integral type conversion attempted on `elements.len()`"
1566 )]
1567 fn overflowing_size() {
1568 Python::with_gil(|py| {
1569 let iter = FaultyIter(0..0, usize::MAX);
1570
1571 let _list = PyList::new(py, iter).unwrap();
1572 })
1573 }
1574
1575 #[test]
1576 fn bad_intopyobject_doesnt_cause_leaks() {
1577 use crate::types::PyInt;
1578 use std::convert::Infallible;
1579 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1580 static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0);
1581
1582 struct Bad(usize);
1583
1584 impl Drop for Bad {
1585 fn drop(&mut self) {
1586 NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst);
1587 }
1588 }
1589
1590 impl<'py> IntoPyObject<'py> for Bad {
1591 type Target = PyInt;
1592 type Output = crate::Bound<'py, Self::Target>;
1593 type Error = Infallible;
1594
1595 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
1596 assert_ne!(self.0, 42);
1598 self.0.into_pyobject(py)
1599 }
1600 }
1601
1602 struct FaultyIter(Range<usize>, usize);
1603
1604 impl Iterator for FaultyIter {
1605 type Item = Bad;
1606
1607 fn next(&mut self) -> Option<Self::Item> {
1608 self.0.next().map(|i| {
1609 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
1610 Bad(i)
1611 })
1612 }
1613 }
1614
1615 impl ExactSizeIterator for FaultyIter {
1616 fn len(&self) -> usize {
1617 self.1
1618 }
1619 }
1620
1621 Python::with_gil(|py| {
1622 std::panic::catch_unwind(|| {
1623 let iter = FaultyIter(0..50, 50);
1624 let _list = PyList::new(py, iter).unwrap();
1625 })
1626 .unwrap_err();
1627 });
1628
1629 assert_eq!(
1630 NEEDS_DESTRUCTING_COUNT.load(SeqCst),
1631 0,
1632 "Some destructors did not run"
1633 );
1634 }
1635
1636 #[test]
1637 fn test_list_to_tuple() {
1638 Python::with_gil(|py| {
1639 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1640 let tuple = list.to_tuple();
1641 let tuple_expected = PyTuple::new(py, vec![1, 2, 3]).unwrap();
1642 assert!(tuple.eq(tuple_expected).unwrap());
1643 })
1644 }
1645
1646 #[test]
1647 fn test_iter_nth() {
1648 Python::with_gil(|py| {
1649 let v = vec![6, 7, 8, 9, 10];
1650 let ob = (&v).into_pyobject(py).unwrap();
1651 let list = ob.downcast::<PyList>().unwrap();
1652
1653 let mut iter = list.iter();
1654 iter.next();
1655 assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 8);
1656 assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 10);
1657 assert!(iter.nth(1).is_none());
1658
1659 let v: Vec<i32> = vec![];
1660 let ob = (&v).into_pyobject(py).unwrap();
1661 let list = ob.downcast::<PyList>().unwrap();
1662
1663 let mut iter = list.iter();
1664 iter.next();
1665 assert!(iter.nth(1).is_none());
1666
1667 let v = vec![1, 2, 3];
1668 let ob = (&v).into_pyobject(py).unwrap();
1669 let list = ob.downcast::<PyList>().unwrap();
1670
1671 let mut iter = list.iter();
1672 assert!(iter.nth(10).is_none());
1673
1674 let v = vec![6, 7, 8, 9, 10];
1675 let ob = (&v).into_pyobject(py).unwrap();
1676 let list = ob.downcast::<PyList>().unwrap();
1677 let mut iter = list.iter();
1678 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 6);
1679 assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 9);
1680 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 10);
1681
1682 let mut iter = list.iter();
1683 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 9);
1684 assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 8);
1685 assert!(iter.next().is_none());
1686 });
1687 }
1688
1689 #[test]
1690 fn test_iter_nth_back() {
1691 Python::with_gil(|py| {
1692 let v = vec![1, 2, 3, 4, 5];
1693 let ob = (&v).into_pyobject(py).unwrap();
1694 let list = ob.downcast::<PyList>().unwrap();
1695
1696 let mut iter = list.iter();
1697 assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 5);
1698 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1699 assert!(iter.nth_back(2).is_none());
1700
1701 let v: Vec<i32> = vec![];
1702 let ob = (&v).into_pyobject(py).unwrap();
1703 let list = ob.downcast::<PyList>().unwrap();
1704
1705 let mut iter = list.iter();
1706 assert!(iter.nth_back(0).is_none());
1707 assert!(iter.nth_back(1).is_none());
1708
1709 let v = vec![1, 2, 3];
1710 let ob = (&v).into_pyobject(py).unwrap();
1711 let list = ob.downcast::<PyList>().unwrap();
1712
1713 let mut iter = list.iter();
1714 assert!(iter.nth_back(5).is_none());
1715
1716 let v = vec![1, 2, 3, 4, 5];
1717 let ob = (&v).into_pyobject(py).unwrap();
1718 let list = ob.downcast::<PyList>().unwrap();
1719
1720 let mut iter = list.iter();
1721 iter.next_back(); assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1723 assert_eq!(iter.next_back().unwrap().extract::<i32>().unwrap(), 2);
1724 assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 1);
1725
1726 let v = vec![1, 2, 3, 4, 5];
1727 let ob = (&v).into_pyobject(py).unwrap();
1728 let list = ob.downcast::<PyList>().unwrap();
1729
1730 let mut iter = list.iter();
1731 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 4);
1732 assert_eq!(iter.nth_back(2).unwrap().extract::<i32>().unwrap(), 1);
1733
1734 let mut iter2 = list.iter();
1735 iter2.next_back();
1736 assert_eq!(iter2.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1737 assert_eq!(iter2.next_back().unwrap().extract::<i32>().unwrap(), 2);
1738
1739 let mut iter3 = list.iter();
1740 iter3.nth(1);
1741 assert_eq!(iter3.nth_back(2).unwrap().extract::<i32>().unwrap(), 3);
1742 assert!(iter3.nth_back(0).is_none());
1743 });
1744 }
1745
1746 #[cfg(feature = "nightly")]
1747 #[test]
1748 fn test_iter_advance_by() {
1749 Python::with_gil(|py| {
1750 let v = vec![1, 2, 3, 4, 5];
1751 let ob = (&v).into_pyobject(py).unwrap();
1752 let list = ob.downcast::<PyList>().unwrap();
1753
1754 let mut iter = list.iter();
1755 assert_eq!(iter.advance_by(2), Ok(()));
1756 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
1757 assert_eq!(iter.advance_by(0), Ok(()));
1758 assert_eq!(iter.advance_by(100), Err(NonZero::new(98).unwrap()));
1759
1760 let mut iter2 = list.iter();
1761 assert_eq!(iter2.advance_by(6), Err(NonZero::new(1).unwrap()));
1762
1763 let mut iter3 = list.iter();
1764 assert_eq!(iter3.advance_by(5), Ok(()));
1765
1766 let mut iter4 = list.iter();
1767 assert_eq!(iter4.advance_by(0), Ok(()));
1768 assert_eq!(iter4.next().unwrap().extract::<i32>().unwrap(), 1);
1769 })
1770 }
1771
1772 #[cfg(feature = "nightly")]
1773 #[test]
1774 fn test_iter_advance_back_by() {
1775 Python::with_gil(|py| {
1776 let v = vec![1, 2, 3, 4, 5];
1777 let ob = (&v).into_pyobject(py).unwrap();
1778 let list = ob.downcast::<PyList>().unwrap();
1779
1780 let mut iter = list.iter();
1781 assert_eq!(iter.advance_back_by(2), Ok(()));
1782 assert_eq!(iter.next_back().unwrap().extract::<i32>().unwrap(), 3);
1783 assert_eq!(iter.advance_back_by(0), Ok(()));
1784 assert_eq!(iter.advance_back_by(100), Err(NonZero::new(98).unwrap()));
1785
1786 let mut iter2 = list.iter();
1787 assert_eq!(iter2.advance_back_by(6), Err(NonZero::new(1).unwrap()));
1788
1789 let mut iter3 = list.iter();
1790 assert_eq!(iter3.advance_back_by(5), Ok(()));
1791
1792 let mut iter4 = list.iter();
1793 assert_eq!(iter4.advance_back_by(0), Ok(()));
1794 assert_eq!(iter4.next_back().unwrap().extract::<i32>().unwrap(), 5);
1795 })
1796 }
1797
1798 #[test]
1799 fn test_iter_last() {
1800 Python::with_gil(|py| {
1801 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1802 let last = list.iter().last();
1803 assert_eq!(last.unwrap().extract::<i32>().unwrap(), 3);
1804 })
1805 }
1806
1807 #[test]
1808 fn test_iter_count() {
1809 Python::with_gil(|py| {
1810 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1811 assert_eq!(list.iter().count(), 3);
1812 })
1813 }
1814}