Skip to main content

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