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::{Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr, Python};
9use std::iter::FusedIterator;
10#[cfg(feature = "nightly")]
11use std::num::NonZero;
12
13#[repr(transparent)]
21pub struct PyList(PyAny);
22
23pyobject_native_type_core!(PyList, pyobject_native_static_type_object!(ffi::PyList_Type), #checkfunction=ffi::PyList_Check);
24
25#[inline]
26#[track_caller]
27pub(crate) fn try_new_from_iter<'py>(
28 py: Python<'py>,
29 mut elements: impl ExactSizeIterator<Item = PyResult<Bound<'py, PyAny>>>,
30) -> PyResult<Bound<'py, PyList>> {
31 unsafe {
32 let len: Py_ssize_t = elements
34 .len()
35 .try_into()
36 .expect("out of range integral type conversion attempted on `elements.len()`");
37
38 let ptr = ffi::PyList_New(len);
39
40 let list = ptr.assume_owned(py).downcast_into_unchecked();
44
45 let count = (&mut elements)
46 .take(len as usize)
47 .try_fold(0, |count, item| {
48 #[cfg(not(Py_LIMITED_API))]
49 ffi::PyList_SET_ITEM(ptr, count, item?.into_ptr());
50 #[cfg(Py_LIMITED_API)]
51 ffi::PyList_SetItem(ptr, count, item?.into_ptr());
52 Ok::<_, PyErr>(count + 1)
53 })?;
54
55 assert!(elements.next().is_none(), "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation.");
56 assert_eq!(len, count, "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation.");
57
58 Ok(list)
59 }
60}
61
62impl PyList {
63 #[track_caller]
90 pub fn new<'py, T, U>(
91 py: Python<'py>,
92 elements: impl IntoIterator<Item = T, IntoIter = U>,
93 ) -> PyResult<Bound<'py, PyList>>
94 where
95 T: IntoPyObject<'py>,
96 U: ExactSizeIterator<Item = T>,
97 {
98 let iter = elements.into_iter().map(|e| e.into_bound_py_any(py));
99 try_new_from_iter(py, iter)
100 }
101
102 pub fn empty(py: Python<'_>) -> Bound<'_, PyList> {
104 unsafe {
105 ffi::PyList_New(0)
106 .assume_owned(py)
107 .downcast_into_unchecked()
108 }
109 }
110}
111
112#[doc(alias = "PyList")]
118pub trait PyListMethods<'py>: crate::sealed::Sealed {
119 fn len(&self) -> usize;
121
122 fn is_empty(&self) -> bool;
124
125 fn as_sequence(&self) -> &Bound<'py, PySequence>;
127
128 fn into_sequence(self) -> Bound<'py, PySequence>;
130
131 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
142
143 #[cfg(not(Py_LIMITED_API))]
151 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny>;
152
153 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList>;
158
159 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
163 where
164 I: IntoPyObject<'py>;
165
166 fn del_item(&self, index: usize) -> PyResult<()>;
170
171 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()>;
175
176 fn del_slice(&self, low: usize, high: usize) -> PyResult<()>;
180
181 fn append<I>(&self, item: I) -> PyResult<()>
183 where
184 I: IntoPyObject<'py>;
185
186 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
190 where
191 I: IntoPyObject<'py>;
192
193 fn contains<V>(&self, value: V) -> PyResult<bool>
197 where
198 V: IntoPyObject<'py>;
199
200 fn index<V>(&self, value: V) -> PyResult<usize>
204 where
205 V: IntoPyObject<'py>;
206
207 fn iter(&self) -> BoundListIterator<'py>;
209
210 fn locked_for_each<F>(&self, closure: F) -> PyResult<()>
218 where
219 F: Fn(Bound<'py, PyAny>) -> PyResult<()>;
220
221 fn sort(&self) -> PyResult<()>;
223
224 fn reverse(&self) -> PyResult<()>;
226
227 fn to_tuple(&self) -> Bound<'py, PyTuple>;
231}
232
233impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
234 fn len(&self) -> usize {
236 unsafe {
237 #[cfg(not(Py_LIMITED_API))]
238 let size = ffi::PyList_GET_SIZE(self.as_ptr());
239 #[cfg(Py_LIMITED_API)]
240 let size = ffi::PyList_Size(self.as_ptr());
241
242 size as usize
244 }
245 }
246
247 fn is_empty(&self) -> bool {
249 self.len() == 0
250 }
251
252 fn as_sequence(&self) -> &Bound<'py, PySequence> {
254 unsafe { self.downcast_unchecked() }
255 }
256
257 fn into_sequence(self) -> Bound<'py, PySequence> {
259 unsafe { self.into_any().downcast_into_unchecked() }
260 }
261
262 fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>> {
273 unsafe {
274 ffi::compat::PyList_GetItemRef(self.as_ptr(), index as Py_ssize_t)
275 .assume_owned_or_err(self.py())
276 }
277 }
278
279 #[cfg(not(Py_LIMITED_API))]
285 unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny> {
286 unsafe {
288 ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t)
289 .assume_borrowed(self.py())
290 .to_owned()
291 }
292 }
293
294 fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList> {
299 unsafe {
300 ffi::PyList_GetSlice(self.as_ptr(), get_ssize_index(low), get_ssize_index(high))
301 .assume_owned(self.py())
302 .downcast_into_unchecked()
303 }
304 }
305
306 fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
310 where
311 I: IntoPyObject<'py>,
312 {
313 fn inner(list: &Bound<'_, PyList>, index: usize, item: Bound<'_, PyAny>) -> PyResult<()> {
314 err::error_on_minusone(list.py(), unsafe {
315 ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
316 })
317 }
318
319 let py = self.py();
320 inner(self, index, item.into_bound_py_any(py)?)
321 }
322
323 #[inline]
327 fn del_item(&self, index: usize) -> PyResult<()> {
328 self.as_sequence().del_item(index)
329 }
330
331 #[inline]
335 fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()> {
336 err::error_on_minusone(self.py(), unsafe {
337 ffi::PyList_SetSlice(
338 self.as_ptr(),
339 get_ssize_index(low),
340 get_ssize_index(high),
341 seq.as_ptr(),
342 )
343 })
344 }
345
346 #[inline]
350 fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
351 self.as_sequence().del_slice(low, high)
352 }
353
354 fn append<I>(&self, item: I) -> PyResult<()>
356 where
357 I: IntoPyObject<'py>,
358 {
359 fn inner(list: &Bound<'_, PyList>, item: Borrowed<'_, '_, PyAny>) -> PyResult<()> {
360 err::error_on_minusone(list.py(), unsafe {
361 ffi::PyList_Append(list.as_ptr(), item.as_ptr())
362 })
363 }
364
365 let py = self.py();
366 inner(
367 self,
368 item.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
369 )
370 }
371
372 fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
376 where
377 I: IntoPyObject<'py>,
378 {
379 fn inner(
380 list: &Bound<'_, PyList>,
381 index: usize,
382 item: Borrowed<'_, '_, PyAny>,
383 ) -> PyResult<()> {
384 err::error_on_minusone(list.py(), unsafe {
385 ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
386 })
387 }
388
389 let py = self.py();
390 inner(
391 self,
392 index,
393 item.into_pyobject_or_pyerr(py)?.into_any().as_borrowed(),
394 )
395 }
396
397 #[inline]
401 fn contains<V>(&self, value: V) -> PyResult<bool>
402 where
403 V: IntoPyObject<'py>,
404 {
405 self.as_sequence().contains(value)
406 }
407
408 #[inline]
412 fn index<V>(&self, value: V) -> PyResult<usize>
413 where
414 V: IntoPyObject<'py>,
415 {
416 self.as_sequence().index(value)
417 }
418
419 fn iter(&self) -> BoundListIterator<'py> {
421 BoundListIterator::new(self.clone())
422 }
423
424 fn locked_for_each<F>(&self, closure: F) -> PyResult<()>
426 where
427 F: Fn(Bound<'py, PyAny>) -> PyResult<()>,
428 {
429 crate::sync::with_critical_section(self, || self.iter().try_for_each(closure))
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 .downcast_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::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::{ffi, IntoPyObject, PyResult, Python};
948 #[cfg(feature = "nightly")]
949 use std::num::NonZero;
950
951 #[test]
952 fn test_new() {
953 Python::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|py| {
1008 let obj = py.eval(ffi::c_str!("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.downcast::<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::with_gil(|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::with_gil(|py| {
1042 let cnt;
1043 let obj = py.eval(ffi::c_str!("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::with_gil(|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::with_gil(|py| {
1067 let cnt;
1068 let obj = py.eval(ffi::c_str!("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::with_gil(|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::with_gil(|py| {
1095 let v = vec![2, 3, 5, 7];
1096 let ob = (&v).into_pyobject(py).unwrap();
1097 let list = ob.downcast::<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::with_gil(|py| {
1114 let v = vec![2, 3, 5, 7];
1115 let ob = v.into_pyobject(py).unwrap();
1116 let list = ob.downcast::<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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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!(list.len() == 0);
1225 });
1226 }
1227
1228 #[test]
1229 fn test_iter_rfold() {
1230 Python::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|py| {
1331 let v = vec![2, 3, 5, 7];
1332 let list = PyList::new(py, &v).unwrap();
1333 let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
1334 assert_eq!(v, v2);
1335 });
1336 }
1337
1338 #[test]
1339 fn test_sort() {
1340 Python::with_gil(|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::with_gil(|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::with_gil(|py| {
1375 let array = [1, 2].into_pyobject(py).unwrap();
1376 let list = array.downcast::<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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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
1503 impl ExactSizeIterator for FaultyIter {
1504 fn len(&self) -> usize {
1505 self.1
1506 }
1507 }
1508
1509 #[test]
1510 #[should_panic(
1511 expected = "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation."
1512 )]
1513 fn too_long_iterator() {
1514 Python::with_gil(|py| {
1515 let iter = FaultyIter(0..usize::MAX, 73);
1516 let _list = PyList::new(py, iter).unwrap();
1517 })
1518 }
1519
1520 #[test]
1521 #[should_panic(
1522 expected = "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation."
1523 )]
1524 fn too_short_iterator() {
1525 Python::with_gil(|py| {
1526 let iter = FaultyIter(0..35, 73);
1527 let _list = PyList::new(py, iter).unwrap();
1528 })
1529 }
1530
1531 #[test]
1532 #[should_panic(
1533 expected = "out of range integral type conversion attempted on `elements.len()`"
1534 )]
1535 fn overflowing_size() {
1536 Python::with_gil(|py| {
1537 let iter = FaultyIter(0..0, usize::MAX);
1538
1539 let _list = PyList::new(py, iter).unwrap();
1540 })
1541 }
1542
1543 #[test]
1544 fn bad_intopyobject_doesnt_cause_leaks() {
1545 use crate::types::PyInt;
1546 use std::convert::Infallible;
1547 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1548 static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0);
1549
1550 struct Bad(usize);
1551
1552 impl Drop for Bad {
1553 fn drop(&mut self) {
1554 NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst);
1555 }
1556 }
1557
1558 impl<'py> IntoPyObject<'py> for Bad {
1559 type Target = PyInt;
1560 type Output = crate::Bound<'py, Self::Target>;
1561 type Error = Infallible;
1562
1563 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
1564 assert_ne!(self.0, 42);
1566 self.0.into_pyobject(py)
1567 }
1568 }
1569
1570 struct FaultyIter(Range<usize>, usize);
1571
1572 impl Iterator for FaultyIter {
1573 type Item = Bad;
1574
1575 fn next(&mut self) -> Option<Self::Item> {
1576 self.0.next().map(|i| {
1577 NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
1578 Bad(i)
1579 })
1580 }
1581 }
1582
1583 impl ExactSizeIterator for FaultyIter {
1584 fn len(&self) -> usize {
1585 self.1
1586 }
1587 }
1588
1589 Python::with_gil(|py| {
1590 std::panic::catch_unwind(|| {
1591 let iter = FaultyIter(0..50, 50);
1592 let _list = PyList::new(py, iter).unwrap();
1593 })
1594 .unwrap_err();
1595 });
1596
1597 assert_eq!(
1598 NEEDS_DESTRUCTING_COUNT.load(SeqCst),
1599 0,
1600 "Some destructors did not run"
1601 );
1602 }
1603
1604 #[test]
1605 fn test_list_to_tuple() {
1606 Python::with_gil(|py| {
1607 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1608 let tuple = list.to_tuple();
1609 let tuple_expected = PyTuple::new(py, vec![1, 2, 3]).unwrap();
1610 assert!(tuple.eq(tuple_expected).unwrap());
1611 })
1612 }
1613
1614 #[test]
1615 fn test_iter_nth() {
1616 Python::with_gil(|py| {
1617 let v = vec![6, 7, 8, 9, 10];
1618 let ob = (&v).into_pyobject(py).unwrap();
1619 let list = ob.downcast::<PyList>().unwrap();
1620
1621 let mut iter = list.iter();
1622 iter.next();
1623 assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 8);
1624 assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 10);
1625 assert!(iter.nth(1).is_none());
1626
1627 let v: Vec<i32> = vec![];
1628 let ob = (&v).into_pyobject(py).unwrap();
1629 let list = ob.downcast::<PyList>().unwrap();
1630
1631 let mut iter = list.iter();
1632 iter.next();
1633 assert!(iter.nth(1).is_none());
1634
1635 let v = vec![1, 2, 3];
1636 let ob = (&v).into_pyobject(py).unwrap();
1637 let list = ob.downcast::<PyList>().unwrap();
1638
1639 let mut iter = list.iter();
1640 assert!(iter.nth(10).is_none());
1641
1642 let v = vec![6, 7, 8, 9, 10];
1643 let ob = (&v).into_pyobject(py).unwrap();
1644 let list = ob.downcast::<PyList>().unwrap();
1645 let mut iter = list.iter();
1646 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 6);
1647 assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 9);
1648 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 10);
1649
1650 let mut iter = list.iter();
1651 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 9);
1652 assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 8);
1653 assert!(iter.next().is_none());
1654 });
1655 }
1656
1657 #[test]
1658 fn test_iter_nth_back() {
1659 Python::with_gil(|py| {
1660 let v = vec![1, 2, 3, 4, 5];
1661 let ob = (&v).into_pyobject(py).unwrap();
1662 let list = ob.downcast::<PyList>().unwrap();
1663
1664 let mut iter = list.iter();
1665 assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 5);
1666 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1667 assert!(iter.nth_back(2).is_none());
1668
1669 let v: Vec<i32> = vec![];
1670 let ob = (&v).into_pyobject(py).unwrap();
1671 let list = ob.downcast::<PyList>().unwrap();
1672
1673 let mut iter = list.iter();
1674 assert!(iter.nth_back(0).is_none());
1675 assert!(iter.nth_back(1).is_none());
1676
1677 let v = vec![1, 2, 3];
1678 let ob = (&v).into_pyobject(py).unwrap();
1679 let list = ob.downcast::<PyList>().unwrap();
1680
1681 let mut iter = list.iter();
1682 assert!(iter.nth_back(5).is_none());
1683
1684 let v = vec![1, 2, 3, 4, 5];
1685 let ob = (&v).into_pyobject(py).unwrap();
1686 let list = ob.downcast::<PyList>().unwrap();
1687
1688 let mut iter = list.iter();
1689 iter.next_back(); assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1691 assert_eq!(iter.next_back().unwrap().extract::<i32>().unwrap(), 2);
1692 assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 1);
1693
1694 let v = vec![1, 2, 3, 4, 5];
1695 let ob = (&v).into_pyobject(py).unwrap();
1696 let list = ob.downcast::<PyList>().unwrap();
1697
1698 let mut iter = list.iter();
1699 assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 4);
1700 assert_eq!(iter.nth_back(2).unwrap().extract::<i32>().unwrap(), 1);
1701
1702 let mut iter2 = list.iter();
1703 iter2.next_back();
1704 assert_eq!(iter2.nth_back(1).unwrap().extract::<i32>().unwrap(), 3);
1705 assert_eq!(iter2.next_back().unwrap().extract::<i32>().unwrap(), 2);
1706
1707 let mut iter3 = list.iter();
1708 iter3.nth(1);
1709 assert_eq!(iter3.nth_back(2).unwrap().extract::<i32>().unwrap(), 3);
1710 assert!(iter3.nth_back(0).is_none());
1711 });
1712 }
1713
1714 #[cfg(feature = "nightly")]
1715 #[test]
1716 fn test_iter_advance_by() {
1717 Python::with_gil(|py| {
1718 let v = vec![1, 2, 3, 4, 5];
1719 let ob = (&v).into_pyobject(py).unwrap();
1720 let list = ob.downcast::<PyList>().unwrap();
1721
1722 let mut iter = list.iter();
1723 assert_eq!(iter.advance_by(2), Ok(()));
1724 assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
1725 assert_eq!(iter.advance_by(0), Ok(()));
1726 assert_eq!(iter.advance_by(100), Err(NonZero::new(98).unwrap()));
1727
1728 let mut iter2 = list.iter();
1729 assert_eq!(iter2.advance_by(6), Err(NonZero::new(1).unwrap()));
1730
1731 let mut iter3 = list.iter();
1732 assert_eq!(iter3.advance_by(5), Ok(()));
1733
1734 let mut iter4 = list.iter();
1735 assert_eq!(iter4.advance_by(0), Ok(()));
1736 assert_eq!(iter4.next().unwrap().extract::<i32>().unwrap(), 1);
1737 })
1738 }
1739
1740 #[cfg(feature = "nightly")]
1741 #[test]
1742 fn test_iter_advance_back_by() {
1743 Python::with_gil(|py| {
1744 let v = vec![1, 2, 3, 4, 5];
1745 let ob = (&v).into_pyobject(py).unwrap();
1746 let list = ob.downcast::<PyList>().unwrap();
1747
1748 let mut iter = list.iter();
1749 assert_eq!(iter.advance_back_by(2), Ok(()));
1750 assert_eq!(iter.next_back().unwrap().extract::<i32>().unwrap(), 3);
1751 assert_eq!(iter.advance_back_by(0), Ok(()));
1752 assert_eq!(iter.advance_back_by(100), Err(NonZero::new(98).unwrap()));
1753
1754 let mut iter2 = list.iter();
1755 assert_eq!(iter2.advance_back_by(6), Err(NonZero::new(1).unwrap()));
1756
1757 let mut iter3 = list.iter();
1758 assert_eq!(iter3.advance_back_by(5), Ok(()));
1759
1760 let mut iter4 = list.iter();
1761 assert_eq!(iter4.advance_back_by(0), Ok(()));
1762 assert_eq!(iter4.next_back().unwrap().extract::<i32>().unwrap(), 5);
1763 })
1764 }
1765
1766 #[test]
1767 fn test_iter_last() {
1768 Python::with_gil(|py| {
1769 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1770 let last = list.iter().last();
1771 assert_eq!(last.unwrap().extract::<i32>().unwrap(), 3);
1772 })
1773 }
1774
1775 #[test]
1776 fn test_iter_count() {
1777 Python::with_gil(|py| {
1778 let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1779 assert_eq!(list.iter().count(), 3);
1780 })
1781 }
1782}