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::sequence::PySequenceMethods;
6use crate::types::{PySequence, PyTuple};
7use crate::{Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr, Python};
8use std::iter::FusedIterator;
9#[cfg(feature = "nightly")]
10use std::num::NonZero;
11
12#[repr(transparent)]
20pub struct PyList(PyAny);
21
22pyobject_native_type_core!(
23 PyList,
24 pyobject_native_static_type_object!(ffi::PyList_Type),
25 "builtins", "list",
26 #checkfunction=ffi::PyList_Check
27);
28
29#[cfg(Py_3_12)]
30impl crate::impl_::pyclass::PyClassBaseType for PyList {
31 type LayoutAsBase = crate::impl_::pycell::PyVariableClassObjectBase;
32 type BaseNativeType = Self;
33 type Initializer = crate::impl_::pyclass_init::PyNativeTypeInitializer<Self>;
34 type PyClassMutability = crate::pycell::impl_::ImmutableClass;
35 type Layout<T: crate::impl_::pyclass::PyClassImpl> =
36 crate::impl_::pycell::PyVariableClassObject<T>;
37}
38
39impl PyList {
40 #[track_caller]
64 pub fn new<'py, T>(
65 py: Python<'py>,
66 elements: impl IntoIterator<Item = T>,
67 ) -> PyResult<Bound<'py, PyList>>
68 where
69 T: IntoPyObject<'py>,
70 {
71 let mut elements = elements.into_iter().map(|e| e.into_bound_py_any(py));
72 let (min_len, _) = elements.size_hint();
73
74 let len: Py_ssize_t = min_len
76 .try_into()
77 .expect("out of range integral type conversion attempted on `elements.len()`");
78
79 let list = unsafe { ffi::PyList_New(len).assume_owned(py).cast_into_unchecked() };
80
81 let count = (&mut elements)
82 .take(len as usize)
83 .try_fold(0, |count, item| unsafe {
84 #[cfg(not(Py_LIMITED_API))]
85 ffi::PyList_SET_ITEM(list.as_ptr(), count, item?.into_ptr());
86 #[cfg(Py_LIMITED_API)]
87 ffi::PyList_SetItem(list.as_ptr(), count, item?.into_ptr());
88 Ok::<_, PyErr>(count + 1)
89 })?;
90
91 assert_eq!(len, count, "Attempted to create PyList but `elements` was smaller than reported by its `size_hint` implementation.");
92
93 elements.try_for_each(|item| list.append(item?))?;
94
95 Ok(list)
96 }
97
98 pub fn empty(py: Python<'_>) -> Bound<'_, PyList> {
100 unsafe { ffi::PyList_New(0).assume_owned(py).cast_into_unchecked() }
101 }
102}
103
104#[doc(alias = "PyList")]
110pub trait PyListMethods<'py>: crate::sealed::Sealed {
111 fn len(&self) -> usize;
113
114 fn is_empty(&self) -> bool;
116
117 fn as_sequence(&self) -> &Bound<'py, PySequence>;
119
120 fn into_sequence(self) -> Bound<'py, PySequence>;
122
123 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
134
135 #[cfg(not(Py_LIMITED_API))]
148 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny>;
149
150 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList>;
155
156 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
160 where
161 I: IntoPyObject<'py>;
162
163 fn del_item(&self, index: usize) -> PyResult<()>;
167
168 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()>;
172
173 fn del_slice(&self, low: usize, high: usize) -> PyResult<()>;
177
178 fn append<I>(&self, item: I) -> PyResult<()>
180 where
181 I: IntoPyObject<'py>;
182
183 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
187 where
188 I: IntoPyObject<'py>;
189
190 fn contains<V>(&self, value: V) -> PyResult<bool>
194 where
195 V: IntoPyObject<'py>;
196
197 fn index<V>(&self, value: V) -> PyResult<usize>
201 where
202 V: IntoPyObject<'py>;
203
204 fn iter(&self) -> BoundListIterator<'py>;
206
207 fn locked_for_each<F>(&self, closure: F) -> PyResult<()>
215 where
216 F: Fn(Bound<'py, PyAny>) -> PyResult<()>;
217
218 fn sort(&self) -> PyResult<()>;
220
221 fn reverse(&self) -> PyResult<()>;
223
224 fn to_tuple(&self) -> Bound<'py, PyTuple>;
228}
229
230impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
231 fn len(&self) -> usize {
233 unsafe {
234 #[cfg(not(Py_LIMITED_API))]
235 let size = ffi::PyList_GET_SIZE(self.as_ptr());
236 #[cfg(Py_LIMITED_API)]
237 let size = ffi::PyList_Size(self.as_ptr());
238
239 size as usize
241 }
242 }
243
244 fn is_empty(&self) -> bool {
246 self.len() == 0
247 }
248
249 fn as_sequence(&self) -> &Bound<'py, PySequence> {
251 unsafe { self.cast_unchecked() }
252 }
253
254 fn into_sequence(self) -> Bound<'py, PySequence> {
256 unsafe { self.cast_into_unchecked() }
257 }
258
259 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
270 unsafe {
271 ffi::compat::PyList_GetItemRef(self.as_ptr(), index as Py_ssize_t)
272 .assume_owned_or_err(self.py())
273 }
274 }
275
276 #[cfg(not(Py_LIMITED_API))]
282 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny> {
283 unsafe {
285 ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t)
286 .assume_borrowed_unchecked(self.py())
287 }
288 .to_owned()
290 }
291
292 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList> {
297 unsafe {
298 ffi::PyList_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
299 .assume_owned(self.py())
300 .cast_into_unchecked()
301 }
302 }
303
304 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
308 where
309 I: IntoPyObject<'py>,
310 {
311 fn inner(list: &Bound<'_, PyList>, index: usize, item: Bound<'_, PyAny>) -> PyResult<()> {
312 err::error_on_minusone(list.py(), unsafe {
313 ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
314 })
315 }
316
317 let py = self.py();
318 inner(self, index, item.into_bound_py_any(py)?)
319 }
320
321 #[inline]
325 fn del_item(&self, index: usize) -> PyResult<()> {
326 self.as_sequence().del_item(index)
327 }
328
329 #[inline]
333 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()> {
334 err::error_on_minusone(self.py(), unsafe {
335 ffi::PyList_SetSlice(
336 self.as_ptr(),
337 get_ssize_index(low),
338 get_ssize_index(high),
339 seq.as_ptr(),
340 )
341 })
342 }
343
344 #[inline]
348 fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
349 self.as_sequence().del_slice(low, high)
350 }
351
352 fn append<I>(&self, item: I) -> PyResult<()>
354 where
355 I: IntoPyObject<'py>,
356 {
357 fn inner(list: &Bound<'_, PyList>, item: Borrowed<'_, '_, PyAny>) -> PyResult<()> {
358 err::error_on_minusone(list.py(), unsafe {
359 ffi::PyList_Append(list.as_ptr(), item.as_ptr())
360 })
361 }
362
363 let py = self.py();
364 inner(
365 self,
366 item.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
367 )
368 }
369
370 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
374 where
375 I: IntoPyObject<'py>,
376 {
377 fn inner(
378 list: &Bound<'_, PyList>,
379 index: usize,
380 item: Borrowed<'_, '_, PyAny>,
381 ) -> PyResult<()> {
382 err::error_on_minusone(list.py(), unsafe {
383 ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
384 })
385 }
386
387 let py = self.py();
388 inner(
389 self,
390 index,
391 item.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
392 )
393 }
394
395 #[inline]
399 fn contains<V>(&self, value: V) -> PyResult<bool>
400 where
401 V: IntoPyObject<'py>,
402 {
403 self.as_sequence().contains(value)
404 }
405
406 #[inline]
410 fn index<V>(&self, value: V) -> PyResult<usize>
411 where
412 V: IntoPyObject<'py>,
413 {
414 self.as_sequence().index(value)
415 }
416
417 fn iter(&self) -> BoundListIterator<'py> {
419 BoundListIterator::new(self.clone())
420 }
421
422 fn locked_for_each<F>(&self, closure: F) -> PyResult<()>
424 where
425 F: Fn(Bound<'py, PyAny>) -> PyResult<()>,
426 {
427 crate::sync::critical_section::with_critical_section(self, || {
428 self.iter().try_for_each(closure)
429 })
430 }
431
432 fn sort(&self) -> PyResult<()> {
434 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
435 }
436
437 fn reverse(&self) -> PyResult<()> {
439 err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
440 }
441
442 fn to_tuple(&self) -> Bound<'py, PyTuple> {
446 unsafe {
447 ffi::PyList_AsTuple(self.as_ptr())
448 .assume_owned(self.py())
449 .cast_into_unchecked()
450 }
451 }
452}
453
454struct Index(usize);
457struct Length(usize);
458
459pub struct BoundListIterator<'py> {
461 list: Bound<'py, PyList>,
462 index: Index,
463 length: Length,
464}
465
466impl<'py> BoundListIterator<'py> {
467 fn new(list: Bound<'py, PyList>) -> Self {
468 Self {
469 index: Index(0),
470 length: Length(list.len()),
471 list,
472 }
473 }
474
475 #[inline]
481 #[cfg(not(Py_LIMITED_API))]
482 #[deny(unsafe_op_in_unsafe_fn)]
483 unsafe fn next_unchecked(
484 index: &mut Index,
485 length: &mut Length,
486 list: &Bound<'py, PyList>,
487 ) -> Option<Bound<'py, PyAny>> {
488 let length = length.0.min(list.len());
489 let my_index = index.0;
490
491 if index.0 < length {
492 let item = unsafe { list.get_item_unchecked(my_index) };
493 index.0 += 1;
494 Some(item)
495 } else {
496 None
497 }
498 }
499
500 #[cfg(Py_LIMITED_API)]
501 fn next(
502 index: &mut Index,
503 length: &mut Length,
504 list: &Bound<'py, PyList>,
505 ) -> Option<Bound<'py, PyAny>> {
506 let length = length.0.min(list.len());
507 let my_index = index.0;
508
509 if index.0 < length {
510 let item = list.get_item(my_index).expect("get-item failed");
511 index.0 += 1;
512 Some(item)
513 } else {
514 None
515 }
516 }
517
518 #[inline]
519 #[cfg(not(feature = "nightly"))]
520 fn nth(
521 index: &mut Index,
522 length: &mut Length,
523 list: &Bound<'py, PyList>,
524 n: usize,
525 ) -> Option<Bound<'py, PyAny>> {
526 let length = length.0.min(list.len());
527 let target_index = index.0 + n;
528 if target_index < length {
529 let item = {
530 #[cfg(Py_LIMITED_API)]
531 {
532 list.get_item(target_index).expect("get-item failed")
533 }
534
535 #[cfg(not(Py_LIMITED_API))]
536 {
537 unsafe { list.get_item_unchecked(target_index) }
538 }
539 };
540 index.0 = target_index + 1;
541 Some(item)
542 } else {
543 None
544 }
545 }
546
547 #[inline]
553 #[cfg(not(Py_LIMITED_API))]
554 #[deny(unsafe_op_in_unsafe_fn)]
555 unsafe fn next_back_unchecked(
556 index: &mut Index,
557 length: &mut Length,
558 list: &Bound<'py, PyList>,
559 ) -> Option<Bound<'py, PyAny>> {
560 let current_length = length.0.min(list.len());
561
562 if index.0 < current_length {
563 let item = unsafe { list.get_item_unchecked(current_length - 1) };
564 length.0 = current_length - 1;
565 Some(item)
566 } else {
567 None
568 }
569 }
570
571 #[inline]
572 #[cfg(Py_LIMITED_API)]
573 fn next_back(
574 index: &mut Index,
575 length: &mut Length,
576 list: &Bound<'py, PyList>,
577 ) -> Option<Bound<'py, PyAny>> {
578 let current_length = (length.0).min(list.len());
579
580 if index.0 < current_length {
581 let item = list.get_item(current_length - 1).expect("get-item failed");
582 length.0 = current_length - 1;
583 Some(item)
584 } else {
585 None
586 }
587 }
588
589 #[inline]
590 #[cfg(not(feature = "nightly"))]
591 fn nth_back(
592 index: &mut Index,
593 length: &mut Length,
594 list: &Bound<'py, PyList>,
595 n: usize,
596 ) -> Option<Bound<'py, PyAny>> {
597 let length_size = length.0.min(list.len());
598 if index.0 + n < length_size {
599 let target_index = length_size - n - 1;
600 let item = {
601 #[cfg(not(Py_LIMITED_API))]
602 {
603 unsafe { list.get_item_unchecked(target_index) }
604 }
605
606 #[cfg(Py_LIMITED_API)]
607 {
608 list.get_item(target_index).expect("get-item failed")
609 }
610 };
611 length.0 = target_index;
612 Some(item)
613 } else {
614 None
615 }
616 }
617
618 #[allow(dead_code)]
619 fn with_critical_section<R>(
620 &mut self,
621 f: impl FnOnce(&mut Index, &mut Length, &Bound<'py, PyList>) -> R,
622 ) -> R {
623 let Self {
624 index,
625 length,
626 list,
627 } = self;
628 crate::sync::critical_section::with_critical_section(list, || f(index, length, list))
629 }
630}
631
632impl<'py> Iterator for BoundListIterator<'py> {
633 type Item = Bound<'py, PyAny>;
634
635 #[inline]
636 fn next(&mut self) -> Option<Self::Item> {
637 #[cfg(not(Py_LIMITED_API))]
638 {
639 self.with_critical_section(|index, length, list| unsafe {
640 Self::next_unchecked(index, length, list)
641 })
642 }
643 #[cfg(Py_LIMITED_API)]
644 {
645 let Self {
646 index,
647 length,
648 list,
649 } = self;
650 Self::next(index, length, list)
651 }
652 }
653
654 #[inline]
655 #[cfg(not(feature = "nightly"))]
656 fn nth(&mut self, n: usize) -> Option<Self::Item> {
657 self.with_critical_section(|index, length, list| Self::nth(index, length, list, n))
658 }
659
660 #[inline]
661 fn size_hint(&self) -> (usize, Option<usize>) {
662 let len = self.len();
663 (len, Some(len))
664 }
665
666 #[inline]
667 fn count(self) -> usize
668 where
669 Self: Sized,
670 {
671 self.len()
672 }
673
674 #[inline]
675 fn last(mut self) -> Option<Self::Item>
676 where
677 Self: Sized,
678 {
679 self.next_back()
680 }
681
682 #[inline]
683 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
684 fn fold<B, F>(mut self, init: B, mut f: F) -> B
685 where
686 Self: Sized,
687 F: FnMut(B, Self::Item) -> B,
688 {
689 self.with_critical_section(|index, length, list| {
690 let mut accum = init;
691 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
692 accum = f(accum, x);
693 }
694 accum
695 })
696 }
697
698 #[inline]
699 #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
700 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
701 where
702 Self: Sized,
703 F: FnMut(B, Self::Item) -> R,
704 R: std::ops::Try<Output = B>,
705 {
706 self.with_critical_section(|index, length, list| {
707 let mut accum = init;
708 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
709 accum = f(accum, x)?
710 }
711 R::from_output(accum)
712 })
713 }
714
715 #[inline]
716 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
717 fn all<F>(&mut self, mut f: F) -> bool
718 where
719 Self: Sized,
720 F: FnMut(Self::Item) -> bool,
721 {
722 self.with_critical_section(|index, length, list| {
723 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
724 if !f(x) {
725 return false;
726 }
727 }
728 true
729 })
730 }
731
732 #[inline]
733 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
734 fn any<F>(&mut self, mut f: F) -> bool
735 where
736 Self: Sized,
737 F: FnMut(Self::Item) -> bool,
738 {
739 self.with_critical_section(|index, length, list| {
740 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
741 if f(x) {
742 return true;
743 }
744 }
745 false
746 })
747 }
748
749 #[inline]
750 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
751 fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
752 where
753 Self: Sized,
754 P: FnMut(&Self::Item) -> bool,
755 {
756 self.with_critical_section(|index, length, list| {
757 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
758 if predicate(&x) {
759 return Some(x);
760 }
761 }
762 None
763 })
764 }
765
766 #[inline]
767 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
768 fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
769 where
770 Self: Sized,
771 F: FnMut(Self::Item) -> Option<B>,
772 {
773 self.with_critical_section(|index, length, list| {
774 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
775 if let found @ Some(_) = f(x) {
776 return found;
777 }
778 }
779 None
780 })
781 }
782
783 #[inline]
784 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
785 fn position<P>(&mut self, mut predicate: P) -> Option<usize>
786 where
787 Self: Sized,
788 P: FnMut(Self::Item) -> bool,
789 {
790 self.with_critical_section(|index, length, list| {
791 let mut acc = 0;
792 while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
793 if predicate(x) {
794 return Some(acc);
795 }
796 acc += 1;
797 }
798 None
799 })
800 }
801
802 #[inline]
803 #[cfg(feature = "nightly")]
804 fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
805 self.with_critical_section(|index, length, list| {
806 let max_len = length.0.min(list.len());
807 let currently_at = index.0;
808 if currently_at >= max_len {
809 if n == 0 {
810 return Ok(());
811 } else {
812 return Err(unsafe { NonZero::new_unchecked(n) });
813 }
814 }
815
816 let items_left = max_len - currently_at;
817 if n <= items_left {
818 index.0 += n;
819 Ok(())
820 } else {
821 index.0 = max_len;
822 let remainder = n - items_left;
823 Err(unsafe { NonZero::new_unchecked(remainder) })
824 }
825 })
826 }
827}
828
829impl DoubleEndedIterator for BoundListIterator<'_> {
830 #[inline]
831 fn next_back(&mut self) -> Option<Self::Item> {
832 #[cfg(not(Py_LIMITED_API))]
833 {
834 self.with_critical_section(|index, length, list| unsafe {
835 Self::next_back_unchecked(index, length, list)
836 })
837 }
838 #[cfg(Py_LIMITED_API)]
839 {
840 let Self {
841 index,
842 length,
843 list,
844 } = self;
845 Self::next_back(index, length, list)
846 }
847 }
848
849 #[inline]
850 #[cfg(not(feature = "nightly"))]
851 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
852 self.with_critical_section(|index, length, list| Self::nth_back(index, length, list, n))
853 }
854
855 #[inline]
856 #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
857 fn rfold<B, F>(mut self, init: B, mut f: F) -> B
858 where
859 Self: Sized,
860 F: FnMut(B, Self::Item) -> B,
861 {
862 self.with_critical_section(|index, length, list| {
863 let mut accum = init;
864 while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
865 accum = f(accum, x);
866 }
867 accum
868 })
869 }
870
871 #[inline]
872 #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
873 fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
874 where
875 Self: Sized,
876 F: FnMut(B, Self::Item) -> R,
877 R: std::ops::Try<Output = B>,
878 {
879 self.with_critical_section(|index, length, list| {
880 let mut accum = init;
881 while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
882 accum = f(accum, x)?
883 }
884 R::from_output(accum)
885 })
886 }
887
888 #[inline]
889 #[cfg(feature = "nightly")]
890 fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
891 self.with_critical_section(|index, length, list| {
892 let max_len = length.0.min(list.len());
893 let currently_at = index.0;
894 if currently_at >= max_len {
895 if n == 0 {
896 return Ok(());
897 } else {
898 return Err(unsafe { NonZero::new_unchecked(n) });
899 }
900 }
901
902 let items_left = max_len - currently_at;
903 if n <= items_left {
904 length.0 = max_len - n;
905 Ok(())
906 } else {
907 length.0 = currently_at;
908 let remainder = n - items_left;
909 Err(unsafe { NonZero::new_unchecked(remainder) })
910 }
911 })
912 }
913}
914
915impl ExactSizeIterator for BoundListIterator<'_> {
916 fn len(&self) -> usize {
917 self.length.0.saturating_sub(self.index.0)
918 }
919}
920
921impl FusedIterator for BoundListIterator<'_> {}
922
923impl<'py> IntoIterator for Bound<'py, PyList> {
924 type Item = Bound<'py, PyAny>;
925 type IntoIter = BoundListIterator<'py>;
926
927 fn into_iter(self) -> Self::IntoIter {
928 BoundListIterator::new(self)
929 }
930}
931
932impl<'py> IntoIterator for &Bound<'py, PyList> {
933 type Item = Bound<'py, PyAny>;
934 type IntoIter = BoundListIterator<'py>;
935
936 fn into_iter(self) -> Self::IntoIter {
937 self.iter()
938 }
939}
940
941#[cfg(test)]
942mod tests {
943 use crate::types::any::PyAnyMethods;
944 use crate::types::list::PyListMethods;
945 use crate::types::sequence::PySequenceMethods;
946 use crate::types::{PyList, PyTuple};
947 use crate::{IntoPyObject, PyResult, Python};
948 #[cfg(feature = "nightly")]
949 use std::num::NonZero;
950
951 #[test]
952 fn test_new() {
953 Python::attach(|py| {
954 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
955 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
956 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
957 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
958 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
959 });
960 }
961
962 #[test]
963 fn test_len() {
964 Python::attach(|py| {
965 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
966 assert_eq!(4, list.len());
967 });
968 }
969
970 #[test]
971 fn test_get_item() {
972 Python::attach(|py| {
973 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
974 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
975 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
976 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
977 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
978 });
979 }
980
981 #[test]
982 fn test_get_slice() {
983 Python::attach(|py| {
984 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
985 let slice = list.get_slice(1, 3);
986 assert_eq!(2, slice.len());
987 let slice = list.get_slice(1, 7);
988 assert_eq!(3, slice.len());
989 });
990 }
991
992 #[test]
993 fn test_set_item() {
994 Python::attach(|py| {
995 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
996 let val = 42i32.into_pyobject(py).unwrap();
997 let val2 = 42i32.into_pyobject(py).unwrap();
998 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
999 list.set_item(0, val).unwrap();
1000 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
1001 assert!(list.set_item(10, val2).is_err());
1002 });
1003 }
1004
1005 #[test]
1006 fn test_set_item_refcnt() {
1007 Python::attach(|py| {
1008 let obj = py.eval(c"object()", None, None).unwrap();
1009 let cnt;
1010 {
1011 let v = vec![2];
1012 let ob = v.into_pyobject(py).unwrap();
1013 let list = ob.cast::<PyList>().unwrap();
1014 cnt = obj._get_refcnt();
1015 list.set_item(0, &obj).unwrap();
1016 }
1017
1018 assert_eq!(cnt, obj._get_refcnt());
1019 });
1020 }
1021
1022 #[test]
1023 fn test_insert() {
1024 Python::attach(|py| {
1025 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1026 let val = 42i32.into_pyobject(py).unwrap();
1027 let val2 = 43i32.into_pyobject(py).unwrap();
1028 assert_eq!(4, list.len());
1029 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1030 list.insert(0, val).unwrap();
1031 list.insert(1000, val2).unwrap();
1032 assert_eq!(6, list.len());
1033 assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
1034 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
1035 assert_eq!(43, list.get_item(5).unwrap().extract::<i32>().unwrap());
1036 });
1037 }
1038
1039 #[test]
1040 fn test_insert_refcnt() {
1041 Python::attach(|py| {
1042 let cnt;
1043 let obj = py.eval(c"object()", None, None).unwrap();
1044 {
1045 let list = PyList::empty(py);
1046 cnt = obj._get_refcnt();
1047 list.insert(0, &obj).unwrap();
1048 }
1049
1050 assert_eq!(cnt, obj._get_refcnt());
1051 });
1052 }
1053
1054 #[test]
1055 fn test_append() {
1056 Python::attach(|py| {
1057 let list = PyList::new(py, [2]).unwrap();
1058 list.append(3).unwrap();
1059 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1060 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1061 });
1062 }
1063
1064 #[test]
1065 fn test_append_refcnt() {
1066 Python::attach(|py| {
1067 let cnt;
1068 let obj = py.eval(c"object()", None, None).unwrap();
1069 {
1070 let list = PyList::empty(py);
1071 cnt = obj._get_refcnt();
1072 list.append(&obj).unwrap();
1073 }
1074 assert_eq!(cnt, obj._get_refcnt());
1075 });
1076 }
1077
1078 #[test]
1079 fn test_iter() {
1080 Python::attach(|py| {
1081 let v = vec![2, 3, 5, 7];
1082 let list = PyList::new(py, &v).unwrap();
1083 let mut idx = 0;
1084 for el in list {
1085 assert_eq!(v[idx], el.extract::<i32>().unwrap());
1086 idx += 1;
1087 }
1088 assert_eq!(idx, v.len());
1089 });
1090 }
1091
1092 #[test]
1093 fn test_iter_size_hint() {
1094 Python::attach(|py| {
1095 let v = vec![2, 3, 5, 7];
1096 let ob = (&v).into_pyobject(py).unwrap();
1097 let list = ob.cast::<PyList>().unwrap();
1098
1099 let mut iter = list.iter();
1100 assert_eq!(iter.size_hint(), (v.len(), Some(v.len())));
1101 iter.next();
1102 assert_eq!(iter.size_hint(), (v.len() - 1, Some(v.len() - 1)));
1103
1104 for _ in &mut iter {}
1106
1107 assert_eq!(iter.size_hint(), (0, Some(0)));
1108 });
1109 }
1110
1111 #[test]
1112 fn test_iter_rev() {
1113 Python::attach(|py| {
1114 let v = vec![2, 3, 5, 7];
1115 let ob = v.into_pyobject(py).unwrap();
1116 let list = ob.cast::<PyList>().unwrap();
1117
1118 let mut iter = list.iter().rev();
1119
1120 assert_eq!(iter.size_hint(), (4, Some(4)));
1121
1122 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 7);
1123 assert_eq!(iter.size_hint(), (3, Some(3)));
1124
1125 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 5);
1126 assert_eq!(iter.size_hint(), (2, Some(2)));
1127
1128 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
1129 assert_eq!(iter.size_hint(), (1, Some(1)));
1130
1131 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 2);
1132 assert_eq!(iter.size_hint(), (0, Some(0)));
1133
1134 assert!(iter.next().is_none());
1135 assert!(iter.next().is_none());
1136 });
1137 }
1138
1139 #[test]
1140 fn test_iter_all() {
1141 Python::attach(|py| {
1142 let list = PyList::new(py, [true, true, true]).unwrap();
1143 assert!(list.iter().all(|x| x.extract::<bool>().unwrap()));
1144
1145 let list = PyList::new(py, [true, false, true]).unwrap();
1146 assert!(!list.iter().all(|x| x.extract::<bool>().unwrap()));
1147 });
1148 }
1149
1150 #[test]
1151 fn test_iter_any() {
1152 Python::attach(|py| {
1153 let list = PyList::new(py, [true, true, true]).unwrap();
1154 assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1155
1156 let list = PyList::new(py, [true, false, true]).unwrap();
1157 assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1158
1159 let list = PyList::new(py, [false, false, false]).unwrap();
1160 assert!(!list.iter().any(|x| x.extract::<bool>().unwrap()));
1161 });
1162 }
1163
1164 #[test]
1165 fn test_iter_find() {
1166 Python::attach(|py: Python<'_>| {
1167 let list = PyList::new(py, ["hello", "world"]).unwrap();
1168 assert_eq!(
1169 Some("world".to_string()),
1170 list.iter()
1171 .find(|v| v.extract::<String>().unwrap() == "world")
1172 .map(|v| v.extract::<String>().unwrap())
1173 );
1174 assert_eq!(
1175 None,
1176 list.iter()
1177 .find(|v| v.extract::<String>().unwrap() == "foobar")
1178 .map(|v| v.extract::<String>().unwrap())
1179 );
1180 });
1181 }
1182
1183 #[test]
1184 fn test_iter_position() {
1185 Python::attach(|py: Python<'_>| {
1186 let list = PyList::new(py, ["hello", "world"]).unwrap();
1187 assert_eq!(
1188 Some(1),
1189 list.iter()
1190 .position(|v| v.extract::<String>().unwrap() == "world")
1191 );
1192 assert_eq!(
1193 None,
1194 list.iter()
1195 .position(|v| v.extract::<String>().unwrap() == "foobar")
1196 );
1197 });
1198 }
1199
1200 #[test]
1201 fn test_iter_fold() {
1202 Python::attach(|py: Python<'_>| {
1203 let list = PyList::new(py, [1, 2, 3]).unwrap();
1204 let sum = list
1205 .iter()
1206 .fold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1207 assert_eq!(sum, 6);
1208 });
1209 }
1210
1211 #[test]
1212 fn test_iter_fold_out_of_bounds() {
1213 Python::attach(|py: Python<'_>| {
1214 let list = PyList::new(py, [1, 2, 3]).unwrap();
1215 let sum = list.iter().fold(0, |_, _| {
1216 for _ in 0..3 {
1219 list.del_item(0).unwrap();
1220 }
1221 -5
1222 });
1223 assert_eq!(sum, -5);
1224 assert_eq!(list.len(), 0);
1225 });
1226 }
1227
1228 #[test]
1229 fn test_iter_rfold() {
1230 Python::attach(|py: Python<'_>| {
1231 let list = PyList::new(py, [1, 2, 3]).unwrap();
1232 let sum = list
1233 .iter()
1234 .rfold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1235 assert_eq!(sum, 6);
1236 });
1237 }
1238
1239 #[test]
1240 fn test_iter_try_fold() {
1241 Python::attach(|py: Python<'_>| {
1242 let list = PyList::new(py, [1, 2, 3]).unwrap();
1243 let sum = list
1244 .iter()
1245 .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1246 .unwrap();
1247 assert_eq!(sum, 6);
1248
1249 let list = PyList::new(py, ["foo", "bar"]).unwrap();
1250 assert!(list
1251 .iter()
1252 .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1253 .is_err());
1254 });
1255 }
1256
1257 #[test]
1258 fn test_iter_try_rfold() {
1259 Python::attach(|py: Python<'_>| {
1260 let list = PyList::new(py, [1, 2, 3]).unwrap();
1261 let sum = list
1262 .iter()
1263 .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1264 .unwrap();
1265 assert_eq!(sum, 6);
1266
1267 let list = PyList::new(py, ["foo", "bar"]).unwrap();
1268 assert!(list
1269 .iter()
1270 .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1271 .is_err());
1272 });
1273 }
1274
1275 #[test]
1276 fn test_into_iter() {
1277 Python::attach(|py| {
1278 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1279 for (i, item) in list.iter().enumerate() {
1280 assert_eq!((i + 1) as i32, item.extract::<i32>().unwrap());
1281 }
1282 });
1283 }
1284
1285 #[test]
1286 fn test_into_iter_bound() {
1287 use crate::types::any::PyAnyMethods;
1288
1289 Python::attach(|py| {
1290 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1291 let mut items = vec![];
1292 for item in &list {
1293 items.push(item.extract::<i32>().unwrap());
1294 }
1295 assert_eq!(items, vec![1, 2, 3, 4]);
1296 });
1297 }
1298
1299 #[test]
1300 fn test_as_sequence() {
1301 Python::attach(|py| {
1302 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1303
1304 assert_eq!(list.as_sequence().len().unwrap(), 4);
1305 assert_eq!(
1306 list.as_sequence()
1307 .get_item(1)
1308 .unwrap()
1309 .extract::<i32>()
1310 .unwrap(),
1311 2
1312 );
1313 });
1314 }
1315
1316 #[test]
1317 fn test_into_sequence() {
1318 Python::attach(|py| {
1319 let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1320
1321 let sequence = list.into_sequence();
1322
1323 assert_eq!(sequence.len().unwrap(), 4);
1324 assert_eq!(sequence.get_item(1).unwrap().extract::<i32>().unwrap(), 2);
1325 });
1326 }
1327
1328 #[test]
1329 fn test_extract() {
1330 Python::attach(|py| {
1331 let v = vec![2, 3, 5, 7];
1332 let list = PyList::new(py, &v).unwrap();
1333 let v2 = list.as_any().extract::<Vec<i32>>().unwrap();
1334 assert_eq!(v, v2);
1335 });
1336 }
1337
1338 #[test]
1339 fn test_sort() {
1340 Python::attach(|py| {
1341 let v = vec![7, 3, 2, 5];
1342 let list = PyList::new(py, &v).unwrap();
1343 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1344 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1345 assert_eq!(2, list.get_item(2).unwrap().extract::<i32>().unwrap());
1346 assert_eq!(5, list.get_item(3).unwrap().extract::<i32>().unwrap());
1347 list.sort().unwrap();
1348 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1349 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1350 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1351 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1352 });
1353 }
1354
1355 #[test]
1356 fn test_reverse() {
1357 Python::attach(|py| {
1358 let v = vec![2, 3, 5, 7];
1359 let list = PyList::new(py, &v).unwrap();
1360 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1361 assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1362 assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1363 assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1364 list.reverse().unwrap();
1365 assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1366 assert_eq!(5, list.get_item(1).unwrap().extract::<i32>().unwrap());
1367 assert_eq!(3, list.get_item(2).unwrap().extract::<i32>().unwrap());
1368 assert_eq!(2, list.get_item(3).unwrap().extract::<i32>().unwrap());
1369 });
1370 }
1371
1372 #[test]
1373 fn test_array_into_pyobject() {
1374 Python::attach(|py| {
1375 let array = [1, 2].into_pyobject(py).unwrap();
1376 let list = array.cast::<PyList>().unwrap();
1377 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1378 assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
1379 });
1380 }
1381
1382 #[test]
1383 fn test_list_get_item_invalid_index() {
1384 Python::attach(|py| {
1385 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1386 let obj = list.get_item(5);
1387 assert!(obj.is_err());
1388 assert_eq!(
1389 obj.unwrap_err().to_string(),
1390 "IndexError: list index out of range"
1391 );
1392 });
1393 }
1394
1395 #[test]
1396 fn test_list_get_item_sanity() {
1397 Python::attach(|py| {
1398 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1399 let obj = list.get_item(0);
1400 assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
1401 });
1402 }
1403
1404 #[cfg(not(Py_LIMITED_API))]
1405 #[test]
1406 fn test_list_get_item_unchecked_sanity() {
1407 Python::attach(|py| {
1408 let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1409 let obj = unsafe { list.get_item_unchecked(0) };
1410 assert_eq!(obj.extract::<i32>().unwrap(), 2);
1411 });
1412 }
1413
1414 #[test]
1415 fn test_list_del_item() {
1416 Python::attach(|py| {
1417 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1418 assert!(list.del_item(10).is_err());
1419 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1420 assert!(list.del_item(0).is_ok());
1421 assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1422 assert!(list.del_item(0).is_ok());
1423 assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1424 assert!(list.del_item(0).is_ok());
1425 assert_eq!(3, list.get_item(0).unwrap().extract::<i32>().unwrap());
1426 assert!(list.del_item(0).is_ok());
1427 assert_eq!(5, list.get_item(0).unwrap().extract::<i32>().unwrap());
1428 assert!(list.del_item(0).is_ok());
1429 assert_eq!(8, list.get_item(0).unwrap().extract::<i32>().unwrap());
1430 assert!(list.del_item(0).is_ok());
1431 assert_eq!(0, list.len());
1432 assert!(list.del_item(0).is_err());
1433 });
1434 }
1435
1436 #[test]
1437 fn test_list_set_slice() {
1438 Python::attach(|py| {
1439 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1440 let ins = PyList::new(py, [7, 4]).unwrap();
1441 list.set_slice(1, 4, &ins).unwrap();
1442 assert_eq!([1, 7, 4, 5, 8], list.extract::<[i32; 5]>().unwrap());
1443 list.set_slice(3, 100, &PyList::empty(py)).unwrap();
1444 assert_eq!([1, 7, 4], list.extract::<[i32; 3]>().unwrap());
1445 });
1446 }
1447
1448 #[test]
1449 fn test_list_del_slice() {
1450 Python::attach(|py| {
1451 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1452 list.del_slice(1, 4).unwrap();
1453 assert_eq!([1, 5, 8], list.extract::<[i32; 3]>().unwrap());
1454 list.del_slice(1, 100).unwrap();
1455 assert_eq!([1], list.extract::<[i32; 1]>().unwrap());
1456 });
1457 }
1458
1459 #[test]
1460 fn test_list_contains() {
1461 Python::attach(|py| {
1462 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1463 assert_eq!(6, list.len());
1464
1465 let bad_needle = 7i32.into_pyobject(py).unwrap();
1466 assert!(!list.contains(&bad_needle).unwrap());
1467
1468 let good_needle = 8i32.into_pyobject(py).unwrap();
1469 assert!(list.contains(&good_needle).unwrap());
1470
1471 let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1472 assert!(list.contains(&type_coerced_needle).unwrap());
1473 });
1474 }
1475
1476 #[test]
1477 fn test_list_index() {
1478 Python::attach(|py| {
1479 let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1480 assert_eq!(0, list.index(1i32).unwrap());
1481 assert_eq!(2, list.index(2i32).unwrap());
1482 assert_eq!(3, list.index(3i32).unwrap());
1483 assert_eq!(4, list.index(5i32).unwrap());
1484 assert_eq!(5, list.index(8i32).unwrap());
1485 assert!(list.index(42i32).is_err());
1486 });
1487 }
1488
1489 use std::ops::Range;
1490
1491 struct FaultyIter(Range<usize>, usize);
1494
1495 impl Iterator for FaultyIter {
1496 type Item = usize;
1497
1498 fn next(&mut self) -> Option<Self::Item> {
1499 self.0.next()
1500 }
1501
1502 fn size_hint(&self) -> (usize, Option<usize>) {
1503 (self.1, Some(self.1))
1504 }
1505 }
1506
1507 #[test]
1508 #[should_panic(
1509 expected = "Attempted to create PyList but `elements` was smaller than reported by its `size_hint` implementation."
1510 )]
1511 fn too_short_iterator() {
1512 Python::attach(|py| {
1513 let iter = FaultyIter(0..35, 73);
1514 let _list = PyList::new(py, iter).unwrap();
1515 })
1516 }
1517
1518 #[test]
1519 #[should_panic(
1520 expected = "out of range integral type conversion attempted on `elements.len()`"
1521 )]
1522 fn overflowing_size() {
1523 Python::attach(|py| {
1524 let iter = FaultyIter(0..0, usize::MAX);
1525
1526 let _list = PyList::new(py, iter).unwrap();
1527 })
1528 }
1529
1530 #[test]
1531 #[cfg(panic = "unwind")]
1532 fn bad_intopyobject_doesnt_cause_leaks() {
1533 use crate::types::PyInt;
1534 use std::convert::Infallible;
1535 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1536 static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0);
1537
1538 struct Bad(usize);
1539
1540 impl Drop for Bad {
1541 fn drop(&mut self) {
1542 NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst);
1543 }
1544 }
1545
1546 impl<'py> IntoPyObject<'py> for Bad {
1547 type Target = PyInt;
1548 type Output = crate::Bound<'py, Self::Target>;
1549 type Error = Infallible;
1550
1551 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
1552 assert_ne!(self.0, 42);
1554 self.0.into_pyobject(py)
1555 }
1556 }
1557
1558 struct FaultyIter(Range<usize>, usize);
1559
1560 impl Iterator for FaultyIter {
1561 type Item = Bad;
1562
1563 fn next(&mut self) -> Option<Self::Item> {
1564 self.0.next().map(|i| {
1565 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
1566 Bad(i)
1567 })
1568 }
1569
1570 fn size_hint(&self) -> (usize, Option<usize>) {
1571 (self.1, Some(self.1))
1572 }
1573 }
1574
1575 Python::attach(|py| {
1576 std::panic::catch_unwind(|| {
1577 let iter = FaultyIter(0..50, 50);
1578 let _list = PyList::new(py, iter).unwrap();
1579 })
1580 .unwrap_err();
1581 });
1582
1583 assert_eq!(
1584 NEEDS_DESTRUCTING_COUNT.load(SeqCst),
1585 0,
1586 "Some destructors did not run"
1587 );
1588 }
1589
1590 #[test]
1591 fn test_list_to_tuple() {
1592 Python::attach(|py| {
1593 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1594 let tuple = list.to_tuple();
1595 let tuple_expected = PyTuple::new(py, vec![1, 2, 3]).unwrap();
1596 assert!(tuple.eq(tuple_expected).unwrap());
1597 })
1598 }
1599
1600 #[test]
1601 fn test_iter_nth() {
1602 Python::attach(|py| {
1603 let v = vec![6, 7, 8, 9, 10];
1604 let ob = (&v).into_pyobject(py).unwrap();
1605 let list = ob.cast::<PyList>().unwrap();
1606
1607 let mut iter = list.iter();
1608 iter.next();
1609 assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 8);
1610 assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 10);
1611 assert!(iter.nth(1).is_none());
1612
1613 let v: Vec<i32> = vec![];
1614 let ob = (&v).into_pyobject(py).unwrap();
1615 let list = ob.cast::<PyList>().unwrap();
1616
1617 let mut iter = list.iter();
1618 iter.next();
1619 assert!(iter.nth(1).is_none());
1620
1621 let v = vec![1, 2, 3];
1622 let ob = (&v).into_pyobject(py).unwrap();
1623 let list = ob.cast::<PyList>().unwrap();
1624
1625 let mut iter = list.iter();
1626 assert!(iter.nth(10).is_none());
1627
1628 let v = vec![6, 7, 8, 9, 10];
1629 let ob = (&v).into_pyobject(py).unwrap();
1630 let list = ob.cast::<PyList>().unwrap();
1631 let mut iter = list.iter();
1632 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 6);
1633 assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 9);
1634 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 10);
1635
1636 let mut iter = list.iter();
1637 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 9);
1638 assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 8);
1639 assert!(iter.next().is_none());
1640 });
1641 }
1642
1643 #[test]
1644 fn test_iter_nth_back() {
1645 Python::attach(|py| {
1646 let v = vec![1, 2, 3, 4, 5];
1647 let ob = (&v).into_pyobject(py).unwrap();
1648 let list = ob.cast::<PyList>().unwrap();
1649
1650 let mut iter = list.iter();
1651 assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 5);
1652 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1653 assert!(iter.nth_back(2).is_none());
1654
1655 let v: Vec<i32> = vec![];
1656 let ob = (&v).into_pyobject(py).unwrap();
1657 let list = ob.cast::<PyList>().unwrap();
1658
1659 let mut iter = list.iter();
1660 assert!(iter.nth_back(0).is_none());
1661 assert!(iter.nth_back(1).is_none());
1662
1663 let v = vec![1, 2, 3];
1664 let ob = (&v).into_pyobject(py).unwrap();
1665 let list = ob.cast::<PyList>().unwrap();
1666
1667 let mut iter = list.iter();
1668 assert!(iter.nth_back(5).is_none());
1669
1670 let v = vec![1, 2, 3, 4, 5];
1671 let ob = (&v).into_pyobject(py).unwrap();
1672 let list = ob.cast::<PyList>().unwrap();
1673
1674 let mut iter = list.iter();
1675 iter.next_back(); assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1677 assert_eq!(iter.next_back().unwrap().extract::<i32>().unwrap(), 2);
1678 assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 1);
1679
1680 let v = vec![1, 2, 3, 4, 5];
1681 let ob = (&v).into_pyobject(py).unwrap();
1682 let list = ob.cast::<PyList>().unwrap();
1683
1684 let mut iter = list.iter();
1685 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 4);
1686 assert_eq!(iter.nth_back(2).unwrap().extract::<i32>().unwrap(), 1);
1687
1688 let mut iter2 = list.iter();
1689 iter2.next_back();
1690 assert_eq!(iter2.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1691 assert_eq!(iter2.next_back().unwrap().extract::<i32>().unwrap(), 2);
1692
1693 let mut iter3 = list.iter();
1694 iter3.nth(1);
1695 assert_eq!(iter3.nth_back(2).unwrap().extract::<i32>().unwrap(), 3);
1696 assert!(iter3.nth_back(0).is_none());
1697 });
1698 }
1699
1700 #[cfg(feature = "nightly")]
1701 #[test]
1702 fn test_iter_advance_by() {
1703 Python::attach(|py| {
1704 let v = vec![1, 2, 3, 4, 5];
1705 let ob = (&v).into_pyobject(py).unwrap();
1706 let list = ob.cast::<PyList>().unwrap();
1707
1708 let mut iter = list.iter();
1709 assert_eq!(iter.advance_by(2), Ok(()));
1710 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
1711 assert_eq!(iter.advance_by(0), Ok(()));
1712 assert_eq!(iter.advance_by(100), Err(NonZero::new(98).unwrap()));
1713
1714 let mut iter2 = list.iter();
1715 assert_eq!(iter2.advance_by(6), Err(NonZero::new(1).unwrap()));
1716
1717 let mut iter3 = list.iter();
1718 assert_eq!(iter3.advance_by(5), Ok(()));
1719
1720 let mut iter4 = list.iter();
1721 assert_eq!(iter4.advance_by(0), Ok(()));
1722 assert_eq!(iter4.next().unwrap().extract::<i32>().unwrap(), 1);
1723 })
1724 }
1725
1726 #[cfg(feature = "nightly")]
1727 #[test]
1728 fn test_iter_advance_back_by() {
1729 Python::attach(|py| {
1730 let v = vec![1, 2, 3, 4, 5];
1731 let ob = (&v).into_pyobject(py).unwrap();
1732 let list = ob.cast::<PyList>().unwrap();
1733
1734 let mut iter = list.iter();
1735 assert_eq!(iter.advance_back_by(2), Ok(()));
1736 assert_eq!(iter.next_back().unwrap().extract::<i32>().unwrap(), 3);
1737 assert_eq!(iter.advance_back_by(0), Ok(()));
1738 assert_eq!(iter.advance_back_by(100), Err(NonZero::new(98).unwrap()));
1739
1740 let mut iter2 = list.iter();
1741 assert_eq!(iter2.advance_back_by(6), Err(NonZero::new(1).unwrap()));
1742
1743 let mut iter3 = list.iter();
1744 assert_eq!(iter3.advance_back_by(5), Ok(()));
1745
1746 let mut iter4 = list.iter();
1747 assert_eq!(iter4.advance_back_by(0), Ok(()));
1748 assert_eq!(iter4.next_back().unwrap().extract::<i32>().unwrap(), 5);
1749 })
1750 }
1751
1752 #[test]
1753 fn test_iter_last() {
1754 Python::attach(|py| {
1755 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1756 let last = list.iter().last();
1757 assert_eq!(last.unwrap().extract::<i32>().unwrap(), 3);
1758 })
1759 }
1760
1761 #[test]
1762 fn test_iter_count() {
1763 Python::attach(|py| {
1764 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1765 assert_eq!(list.iter().count(), 3);
1766 })
1767 }
1768
1769 #[test]
1770 fn test_new_from_non_exact_iter() {
1771 Python::attach(|py| {
1772 let iter = (0..5)
1773 .filter(|_| true) .map(|item| item.into_pyobject(py).unwrap());
1775
1776 assert!(
1777 matches!(iter.size_hint(), (0, _)),
1778 "size_hint lower bound should be 0 because we do not now the final size after filter"
1779 );
1780
1781 let list = PyList::new(py, iter).unwrap();
1782 assert_eq!(
1783 list.len(),
1784 5,
1785 "list should contain all elements even though size_hint is 0"
1786 );
1787 })
1788 }
1789}