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