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