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