pyo3/types/
list.rs

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/// Represents a Python `list`.
13///
14/// Values of this type are accessed via PyO3's smart pointers, e.g. as
15/// [`Py<PyList>`][crate::Py] or [`Bound<'py, PyList>`][Bound].
16///
17/// For APIs available on `list` objects, see the [`PyListMethods`] trait which is implemented for
18/// [`Bound<'py, PyList>`][Bound].
19#[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        // PyList_New checks for overflow but has a bad error message, so we check ourselves
32        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        // We create the `Bound` pointer here for two reasons:
40        // - panics if the ptr is null
41        // - its Drop cleans up the list if user code or the asserts panic.
42        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    /// Constructs a new list with the given elements.
63    ///
64    /// If you want to create a [`PyList`] with elements of different or unknown types, or from an
65    /// iterable that doesn't implement [`ExactSizeIterator`], use [`PyListMethods::append`].
66    ///
67    /// # Examples
68    ///
69    /// ```rust
70    /// use pyo3::prelude::*;
71    /// use pyo3::types::PyList;
72    ///
73    /// # fn main() -> PyResult<()> {
74    /// Python::attach(|py| {
75    ///     let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
76    ///     let list = PyList::new(py, elements)?;
77    ///     assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5]");
78    /// # Ok(())
79    /// })
80    /// # }
81    /// ```
82    ///
83    /// # Panics
84    ///
85    /// This function will panic if `element`'s [`ExactSizeIterator`] implementation is incorrect.
86    /// All standard library structures implement this trait correctly, if they do, so calling this
87    /// function with (for example) [`Vec`]`<T>` or `&[T]` will always succeed.
88    #[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    /// Constructs a new empty list.
102    pub fn empty(py: Python<'_>) -> Bound<'_, PyList> {
103        unsafe { ffi::PyList_New(0).assume_owned(py).cast_into_unchecked() }
104    }
105}
106
107/// Implementation of functionality for [`PyList`].
108///
109/// These methods are defined for the `Bound<'py, PyList>` smart pointer, so to use method call
110/// syntax these methods are separated into a trait, because stable Rust does not yet support
111/// `arbitrary_self_types`.
112#[doc(alias = "PyList")]
113pub trait PyListMethods<'py>: crate::sealed::Sealed {
114    /// Returns the length of the list.
115    fn len(&self) -> usize;
116
117    /// Checks if the list is empty.
118    fn is_empty(&self) -> bool;
119
120    /// Returns `self` cast as a `PySequence`.
121    fn as_sequence(&self) -> &Bound<'py, PySequence>;
122
123    /// Returns `self` cast as a `PySequence`.
124    fn into_sequence(self) -> Bound<'py, PySequence>;
125
126    /// Gets the list item at the specified index.
127    /// # Example
128    /// ```
129    /// use pyo3::{prelude::*, types::PyList};
130    /// Python::attach(|py| {
131    ///     let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
132    ///     let obj = list.get_item(0);
133    ///     assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
134    /// });
135    /// ```
136    fn get_item(&self, index: usize) -> PyResult<Bound<'py, PyAny>>;
137
138    /// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
139    ///
140    /// # Safety
141    ///
142    /// Caller must verify that the index is within the bounds of the list.
143    /// On the free-threaded build, caller must verify they have exclusive access to the list
144    /// via a lock or by holding the innermost critical section on the list.
145    #[cfg(not(Py_LIMITED_API))]
146    unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny>;
147
148    /// Takes the slice `self[low:high]` and returns it as a new list.
149    ///
150    /// Indices must be nonnegative, and out-of-range indices are clipped to
151    /// `self.len()`.
152    fn get_slice(&self, low: usize, high: usize) -> Bound<'py, PyList>;
153
154    /// Sets the item at the specified index.
155    ///
156    /// Raises `IndexError` if the index is out of range.
157    fn set_item<I>(&self, index: usize, item: I) -> PyResult<()>
158    where
159        I: IntoPyObject<'py>;
160
161    /// Deletes the `index`th element of self.
162    ///
163    /// This is equivalent to the Python statement `del self[i]`.
164    fn del_item(&self, index: usize) -> PyResult<()>;
165
166    /// Assigns the sequence `seq` to the slice of `self` from `low` to `high`.
167    ///
168    /// This is equivalent to the Python statement `self[low:high] = v`.
169    fn set_slice(&self, low: usize, high: usize, seq: &Bound<'_, PyAny>) -> PyResult<()>;
170
171    /// Deletes the slice from `low` to `high` from `self`.
172    ///
173    /// This is equivalent to the Python statement `del self[low:high]`.
174    fn del_slice(&self, low: usize, high: usize) -> PyResult<()>;
175
176    /// Appends an item to the list.
177    fn append<I>(&self, item: I) -> PyResult<()>
178    where
179        I: IntoPyObject<'py>;
180
181    /// Inserts an item at the specified index.
182    ///
183    /// If `index >= self.len()`, inserts at the end.
184    fn insert<I>(&self, index: usize, item: I) -> PyResult<()>
185    where
186        I: IntoPyObject<'py>;
187
188    /// Determines if self contains `value`.
189    ///
190    /// This is equivalent to the Python expression `value in self`.
191    fn contains<V>(&self, value: V) -> PyResult<bool>
192    where
193        V: IntoPyObject<'py>;
194
195    /// Returns the first index `i` for which `self[i] == value`.
196    ///
197    /// This is equivalent to the Python expression `self.index(value)`.
198    fn index<V>(&self, value: V) -> PyResult<usize>
199    where
200        V: IntoPyObject<'py>;
201
202    /// Returns an iterator over this list's items.
203    fn iter(&self) -> BoundListIterator<'py>;
204
205    /// Iterates over the contents of this list while holding a critical section on the list.
206    /// This is useful when the GIL is disabled and the list is shared between threads.
207    /// It is not guaranteed that the list will not be modified during iteration when the
208    /// closure calls arbitrary Python code that releases the critical section held by the
209    /// iterator. Otherwise, the list will not be modified during iteration.
210    ///
211    /// This is equivalent to for_each if the GIL is enabled.
212    fn locked_for_each<F>(&self, closure: F) -> PyResult<()>
213    where
214        F: Fn(Bound<'py, PyAny>) -> PyResult<()>;
215
216    /// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
217    fn sort(&self) -> PyResult<()>;
218
219    /// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
220    fn reverse(&self) -> PyResult<()>;
221
222    /// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.
223    ///
224    /// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`.
225    fn to_tuple(&self) -> Bound<'py, PyTuple>;
226}
227
228impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
229    /// Returns the length of the list.
230    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            // non-negative Py_ssize_t should always fit into Rust usize
238            size as usize
239        }
240    }
241
242    /// Checks if the list is empty.
243    fn is_empty(&self) -> bool {
244        self.len() == 0
245    }
246
247    /// Returns `self` cast as a `PySequence`.
248    fn as_sequence(&self) -> &Bound<'py, PySequence> {
249        unsafe { self.cast_unchecked() }
250    }
251
252    /// Returns `self` cast as a `PySequence`.
253    fn into_sequence(self) -> Bound<'py, PySequence> {
254        unsafe { self.cast_into_unchecked() }
255    }
256
257    /// Gets the list item at the specified index.
258    /// # Example
259    /// ```
260    /// use pyo3::{prelude::*, types::PyList};
261    /// Python::attach(|py| {
262    ///     let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
263    ///     let obj = list.get_item(0);
264    ///     assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
265    /// });
266    /// ```
267    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    /// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution.
275    ///
276    /// # Safety
277    ///
278    /// Caller must verify that the index is within the bounds of the list.
279    #[cfg(not(Py_LIMITED_API))]
280    unsafe fn get_item_unchecked(&self, index: usize) -> Bound<'py, PyAny> {
281        // PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890).
282        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    /// Takes the slice `self[low:high]` and returns it as a new list.
290    ///
291    /// Indices must be nonnegative, and out-of-range indices are clipped to
292    /// `self.len()`.
293    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    /// Sets the item at the specified index.
302    ///
303    /// Raises `IndexError` if the index is out of range.
304    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    /// Deletes the `index`th element of self.
319    ///
320    /// This is equivalent to the Python statement `del self[i]`.
321    #[inline]
322    fn del_item(&self, index: usize) -> PyResult<()> {
323        self.as_sequence().del_item(index)
324    }
325
326    /// Assigns the sequence `seq` to the slice of `self` from `low` to `high`.
327    ///
328    /// This is equivalent to the Python statement `self[low:high] = v`.
329    #[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    /// Deletes the slice from `low` to `high` from `self`.
342    ///
343    /// This is equivalent to the Python statement `del self[low:high]`.
344    #[inline]
345    fn del_slice(&self, low: usize, high: usize) -> PyResult<()> {
346        self.as_sequence().del_slice(low, high)
347    }
348
349    /// Appends an item to the list.
350    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    /// Inserts an item at the specified index.
368    ///
369    /// If `index >= self.len()`, inserts at the end.
370    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    /// Determines if self contains `value`.
393    ///
394    /// This is equivalent to the Python expression `value in self`.
395    #[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    /// Returns the first index `i` for which `self[i] == value`.
404    ///
405    /// This is equivalent to the Python expression `self.index(value)`.
406    #[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    /// Returns an iterator over this list's items.
415    fn iter(&self) -> BoundListIterator<'py> {
416        BoundListIterator::new(self.clone())
417    }
418
419    /// Iterates over a list while holding a critical section, calling a closure on each item
420    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    /// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
428    fn sort(&self) -> PyResult<()> {
429        err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
430    }
431
432    /// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
433    fn reverse(&self) -> PyResult<()> {
434        err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
435    }
436
437    /// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.
438    ///
439    /// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`.
440    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
449// New types for type checking when using BoundListIterator associated methods, like
450// BoundListIterator::next_unchecked.
451struct Index(usize);
452struct Length(usize);
453
454/// Used by `PyList::iter()`.
455pub 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    /// # Safety
471    ///
472    /// On the free-threaded build, caller must verify they have exclusive
473    /// access to the list by holding a lock or by holding the innermost
474    /// critical section on the list.
475    #[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    /// # Safety
543    ///
544    /// On the free-threaded build, caller must verify they have exclusive
545    /// access to the list by holding a lock or by holding the innermost
546    /// critical section on the list.
547    #[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            // Exhaust iterator.
1100            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                // clear the list to create a pathological fold operation
1212                // that mutates the list as it processes it
1213                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    // An iterator that lies about its `ExactSizeIterator` implementation.
1487    // See https://github.com/PyO3/pyo3/issues/2118
1488    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                // This panic should not lead to a memory leak
1560                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(); // Consume the last element
1685            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}