pyo3/types/
list.rs

1use std::iter::FusedIterator;
2
3use crate::err::{self, PyResult};
4use crate::ffi::{self, Py_ssize_t};
5use crate::ffi_ptr_ext::FfiPtrExt;
6use crate::internal_tricks::get_ssize_index;
7use crate::types::{PySequence, PyTuple};
8use crate::{
9    Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr, PyObject, Python,
10};
11
12use crate::types::any::PyAnyMethods;
13use crate::types::sequence::PySequenceMethods;
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    /// # Safety
551    ///
552    /// On the free-threaded build, caller must verify they have exclusive
553    /// access to the list by holding a lock or by holding the innermost
554    /// critical section on the list.
555    #[inline]
556    #[cfg(not(Py_LIMITED_API))]
557    #[deny(unsafe_op_in_unsafe_fn)]
558    unsafe fn next_back_unchecked(
559        index: &mut Index,
560        length: &mut Length,
561        list: &Bound<'py, PyList>,
562    ) -> Option<Bound<'py, PyAny>> {
563        let current_length = length.0.min(list.len());
564
565        if index.0 < current_length {
566            let item = unsafe { list.get_item_unchecked(current_length - 1) };
567            length.0 = current_length - 1;
568            Some(item)
569        } else {
570            None
571        }
572    }
573
574    #[inline]
575    #[cfg(Py_LIMITED_API)]
576    fn next_back(
577        index: &mut Index,
578        length: &mut Length,
579        list: &Bound<'py, PyList>,
580    ) -> Option<Bound<'py, PyAny>> {
581        let current_length = (length.0).min(list.len());
582
583        if index.0 < current_length {
584            let item = list.get_item(current_length - 1).expect("get-item failed");
585            length.0 = current_length - 1;
586            Some(item)
587        } else {
588            None
589        }
590    }
591
592    #[cfg(not(Py_LIMITED_API))]
593    fn with_critical_section<R>(
594        &mut self,
595        f: impl FnOnce(&mut Index, &mut Length, &Bound<'py, PyList>) -> R,
596    ) -> R {
597        let Self {
598            index,
599            length,
600            list,
601        } = self;
602        crate::sync::with_critical_section(list, || f(index, length, list))
603    }
604}
605
606impl<'py> Iterator for BoundListIterator<'py> {
607    type Item = Bound<'py, PyAny>;
608
609    #[inline]
610    fn next(&mut self) -> Option<Self::Item> {
611        #[cfg(not(Py_LIMITED_API))]
612        {
613            self.with_critical_section(|index, length, list| unsafe {
614                Self::next_unchecked(index, length, list)
615            })
616        }
617        #[cfg(Py_LIMITED_API)]
618        {
619            let Self {
620                index,
621                length,
622                list,
623            } = self;
624            Self::next(index, length, list)
625        }
626    }
627
628    #[inline]
629    fn size_hint(&self) -> (usize, Option<usize>) {
630        let len = self.len();
631        (len, Some(len))
632    }
633
634    #[inline]
635    #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
636    fn fold<B, F>(mut self, init: B, mut f: F) -> B
637    where
638        Self: Sized,
639        F: FnMut(B, Self::Item) -> B,
640    {
641        self.with_critical_section(|index, length, list| {
642            let mut accum = init;
643            while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
644                accum = f(accum, x);
645            }
646            accum
647        })
648    }
649
650    #[inline]
651    #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
652    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
653    where
654        Self: Sized,
655        F: FnMut(B, Self::Item) -> R,
656        R: std::ops::Try<Output = B>,
657    {
658        self.with_critical_section(|index, length, list| {
659            let mut accum = init;
660            while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
661                accum = f(accum, x)?
662            }
663            R::from_output(accum)
664        })
665    }
666
667    #[inline]
668    #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
669    fn all<F>(&mut self, mut f: F) -> bool
670    where
671        Self: Sized,
672        F: FnMut(Self::Item) -> bool,
673    {
674        self.with_critical_section(|index, length, list| {
675            while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
676                if !f(x) {
677                    return false;
678                }
679            }
680            true
681        })
682    }
683
684    #[inline]
685    #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
686    fn any<F>(&mut self, mut f: F) -> bool
687    where
688        Self: Sized,
689        F: FnMut(Self::Item) -> bool,
690    {
691        self.with_critical_section(|index, length, list| {
692            while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
693                if f(x) {
694                    return true;
695                }
696            }
697            false
698        })
699    }
700
701    #[inline]
702    #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
703    fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
704    where
705        Self: Sized,
706        P: FnMut(&Self::Item) -> bool,
707    {
708        self.with_critical_section(|index, length, list| {
709            while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
710                if predicate(&x) {
711                    return Some(x);
712                }
713            }
714            None
715        })
716    }
717
718    #[inline]
719    #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
720    fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
721    where
722        Self: Sized,
723        F: FnMut(Self::Item) -> Option<B>,
724    {
725        self.with_critical_section(|index, length, list| {
726            while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
727                if let found @ Some(_) = f(x) {
728                    return found;
729                }
730            }
731            None
732        })
733    }
734
735    #[inline]
736    #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
737    fn position<P>(&mut self, mut predicate: P) -> Option<usize>
738    where
739        Self: Sized,
740        P: FnMut(Self::Item) -> bool,
741    {
742        self.with_critical_section(|index, length, list| {
743            let mut acc = 0;
744            while let Some(x) = unsafe { Self::next_unchecked(index, length, list) } {
745                if predicate(x) {
746                    return Some(acc);
747                }
748                acc += 1;
749            }
750            None
751        })
752    }
753}
754
755impl DoubleEndedIterator for BoundListIterator<'_> {
756    #[inline]
757    fn next_back(&mut self) -> Option<Self::Item> {
758        #[cfg(not(Py_LIMITED_API))]
759        {
760            self.with_critical_section(|index, length, list| unsafe {
761                Self::next_back_unchecked(index, length, list)
762            })
763        }
764        #[cfg(Py_LIMITED_API)]
765        {
766            let Self {
767                index,
768                length,
769                list,
770            } = self;
771            Self::next_back(index, length, list)
772        }
773    }
774
775    #[inline]
776    #[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))]
777    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
778    where
779        Self: Sized,
780        F: FnMut(B, Self::Item) -> B,
781    {
782        self.with_critical_section(|index, length, list| {
783            let mut accum = init;
784            while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
785                accum = f(accum, x);
786            }
787            accum
788        })
789    }
790
791    #[inline]
792    #[cfg(all(Py_GIL_DISABLED, feature = "nightly"))]
793    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
794    where
795        Self: Sized,
796        F: FnMut(B, Self::Item) -> R,
797        R: std::ops::Try<Output = B>,
798    {
799        self.with_critical_section(|index, length, list| {
800            let mut accum = init;
801            while let Some(x) = unsafe { Self::next_back_unchecked(index, length, list) } {
802                accum = f(accum, x)?
803            }
804            R::from_output(accum)
805        })
806    }
807}
808
809impl ExactSizeIterator for BoundListIterator<'_> {
810    fn len(&self) -> usize {
811        self.length.0.saturating_sub(self.index.0)
812    }
813}
814
815impl FusedIterator for BoundListIterator<'_> {}
816
817impl<'py> IntoIterator for Bound<'py, PyList> {
818    type Item = Bound<'py, PyAny>;
819    type IntoIter = BoundListIterator<'py>;
820
821    fn into_iter(self) -> Self::IntoIter {
822        BoundListIterator::new(self)
823    }
824}
825
826impl<'py> IntoIterator for &Bound<'py, PyList> {
827    type Item = Bound<'py, PyAny>;
828    type IntoIter = BoundListIterator<'py>;
829
830    fn into_iter(self) -> Self::IntoIter {
831        self.iter()
832    }
833}
834
835#[cfg(test)]
836mod tests {
837    use crate::types::any::PyAnyMethods;
838    use crate::types::list::PyListMethods;
839    use crate::types::sequence::PySequenceMethods;
840    use crate::types::{PyList, PyTuple};
841    use crate::{ffi, IntoPyObject, PyResult, Python};
842
843    #[test]
844    fn test_new() {
845        Python::with_gil(|py| {
846            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
847            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
848            assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
849            assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
850            assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
851        });
852    }
853
854    #[test]
855    fn test_len() {
856        Python::with_gil(|py| {
857            let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
858            assert_eq!(4, list.len());
859        });
860    }
861
862    #[test]
863    fn test_get_item() {
864        Python::with_gil(|py| {
865            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
866            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
867            assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
868            assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
869            assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
870        });
871    }
872
873    #[test]
874    fn test_get_slice() {
875        Python::with_gil(|py| {
876            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
877            let slice = list.get_slice(1, 3);
878            assert_eq!(2, slice.len());
879            let slice = list.get_slice(1, 7);
880            assert_eq!(3, slice.len());
881        });
882    }
883
884    #[test]
885    fn test_set_item() {
886        Python::with_gil(|py| {
887            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
888            let val = 42i32.into_pyobject(py).unwrap();
889            let val2 = 42i32.into_pyobject(py).unwrap();
890            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
891            list.set_item(0, val).unwrap();
892            assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
893            assert!(list.set_item(10, val2).is_err());
894        });
895    }
896
897    #[test]
898    fn test_set_item_refcnt() {
899        Python::with_gil(|py| {
900            let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
901            let cnt;
902            {
903                let v = vec![2];
904                let ob = v.into_pyobject(py).unwrap();
905                let list = ob.downcast::<PyList>().unwrap();
906                cnt = obj.get_refcnt();
907                list.set_item(0, &obj).unwrap();
908            }
909
910            assert_eq!(cnt, obj.get_refcnt());
911        });
912    }
913
914    #[test]
915    fn test_insert() {
916        Python::with_gil(|py| {
917            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
918            let val = 42i32.into_pyobject(py).unwrap();
919            let val2 = 43i32.into_pyobject(py).unwrap();
920            assert_eq!(4, list.len());
921            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
922            list.insert(0, val).unwrap();
923            list.insert(1000, val2).unwrap();
924            assert_eq!(6, list.len());
925            assert_eq!(42, list.get_item(0).unwrap().extract::<i32>().unwrap());
926            assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
927            assert_eq!(43, list.get_item(5).unwrap().extract::<i32>().unwrap());
928        });
929    }
930
931    #[test]
932    fn test_insert_refcnt() {
933        Python::with_gil(|py| {
934            let cnt;
935            let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
936            {
937                let list = PyList::empty(py);
938                cnt = obj.get_refcnt();
939                list.insert(0, &obj).unwrap();
940            }
941
942            assert_eq!(cnt, obj.get_refcnt());
943        });
944    }
945
946    #[test]
947    fn test_append() {
948        Python::with_gil(|py| {
949            let list = PyList::new(py, [2]).unwrap();
950            list.append(3).unwrap();
951            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
952            assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
953        });
954    }
955
956    #[test]
957    fn test_append_refcnt() {
958        Python::with_gil(|py| {
959            let cnt;
960            let obj = py.eval(ffi::c_str!("object()"), None, None).unwrap();
961            {
962                let list = PyList::empty(py);
963                cnt = obj.get_refcnt();
964                list.append(&obj).unwrap();
965            }
966            assert_eq!(cnt, obj.get_refcnt());
967        });
968    }
969
970    #[test]
971    fn test_iter() {
972        Python::with_gil(|py| {
973            let v = vec![2, 3, 5, 7];
974            let list = PyList::new(py, &v).unwrap();
975            let mut idx = 0;
976            for el in list {
977                assert_eq!(v[idx], el.extract::<i32>().unwrap());
978                idx += 1;
979            }
980            assert_eq!(idx, v.len());
981        });
982    }
983
984    #[test]
985    fn test_iter_size_hint() {
986        Python::with_gil(|py| {
987            let v = vec![2, 3, 5, 7];
988            let ob = (&v).into_pyobject(py).unwrap();
989            let list = ob.downcast::<PyList>().unwrap();
990
991            let mut iter = list.iter();
992            assert_eq!(iter.size_hint(), (v.len(), Some(v.len())));
993            iter.next();
994            assert_eq!(iter.size_hint(), (v.len() - 1, Some(v.len() - 1)));
995
996            // Exhaust iterator.
997            for _ in &mut iter {}
998
999            assert_eq!(iter.size_hint(), (0, Some(0)));
1000        });
1001    }
1002
1003    #[test]
1004    fn test_iter_rev() {
1005        Python::with_gil(|py| {
1006            let v = vec![2, 3, 5, 7];
1007            let ob = v.into_pyobject(py).unwrap();
1008            let list = ob.downcast::<PyList>().unwrap();
1009
1010            let mut iter = list.iter().rev();
1011
1012            assert_eq!(iter.size_hint(), (4, Some(4)));
1013
1014            assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 7);
1015            assert_eq!(iter.size_hint(), (3, Some(3)));
1016
1017            assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 5);
1018            assert_eq!(iter.size_hint(), (2, Some(2)));
1019
1020            assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3);
1021            assert_eq!(iter.size_hint(), (1, Some(1)));
1022
1023            assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 2);
1024            assert_eq!(iter.size_hint(), (0, Some(0)));
1025
1026            assert!(iter.next().is_none());
1027            assert!(iter.next().is_none());
1028        });
1029    }
1030
1031    #[test]
1032    fn test_iter_all() {
1033        Python::with_gil(|py| {
1034            let list = PyList::new(py, [true, true, true]).unwrap();
1035            assert!(list.iter().all(|x| x.extract::<bool>().unwrap()));
1036
1037            let list = PyList::new(py, [true, false, true]).unwrap();
1038            assert!(!list.iter().all(|x| x.extract::<bool>().unwrap()));
1039        });
1040    }
1041
1042    #[test]
1043    fn test_iter_any() {
1044        Python::with_gil(|py| {
1045            let list = PyList::new(py, [true, true, true]).unwrap();
1046            assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1047
1048            let list = PyList::new(py, [true, false, true]).unwrap();
1049            assert!(list.iter().any(|x| x.extract::<bool>().unwrap()));
1050
1051            let list = PyList::new(py, [false, false, false]).unwrap();
1052            assert!(!list.iter().any(|x| x.extract::<bool>().unwrap()));
1053        });
1054    }
1055
1056    #[test]
1057    fn test_iter_find() {
1058        Python::with_gil(|py: Python<'_>| {
1059            let list = PyList::new(py, ["hello", "world"]).unwrap();
1060            assert_eq!(
1061                Some("world".to_string()),
1062                list.iter()
1063                    .find(|v| v.extract::<String>().unwrap() == "world")
1064                    .map(|v| v.extract::<String>().unwrap())
1065            );
1066            assert_eq!(
1067                None,
1068                list.iter()
1069                    .find(|v| v.extract::<String>().unwrap() == "foobar")
1070                    .map(|v| v.extract::<String>().unwrap())
1071            );
1072        });
1073    }
1074
1075    #[test]
1076    fn test_iter_position() {
1077        Python::with_gil(|py: Python<'_>| {
1078            let list = PyList::new(py, ["hello", "world"]).unwrap();
1079            assert_eq!(
1080                Some(1),
1081                list.iter()
1082                    .position(|v| v.extract::<String>().unwrap() == "world")
1083            );
1084            assert_eq!(
1085                None,
1086                list.iter()
1087                    .position(|v| v.extract::<String>().unwrap() == "foobar")
1088            );
1089        });
1090    }
1091
1092    #[test]
1093    fn test_iter_fold() {
1094        Python::with_gil(|py: Python<'_>| {
1095            let list = PyList::new(py, [1, 2, 3]).unwrap();
1096            let sum = list
1097                .iter()
1098                .fold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1099            assert_eq!(sum, 6);
1100        });
1101    }
1102
1103    #[test]
1104    fn test_iter_fold_out_of_bounds() {
1105        Python::with_gil(|py: Python<'_>| {
1106            let list = PyList::new(py, [1, 2, 3]).unwrap();
1107            let sum = list.iter().fold(0, |_, _| {
1108                // clear the list to create a pathological fold operation
1109                // that mutates the list as it processes it
1110                for _ in 0..3 {
1111                    list.del_item(0).unwrap();
1112                }
1113                -5
1114            });
1115            assert_eq!(sum, -5);
1116            assert!(list.len() == 0);
1117        });
1118    }
1119
1120    #[test]
1121    fn test_iter_rfold() {
1122        Python::with_gil(|py: Python<'_>| {
1123            let list = PyList::new(py, [1, 2, 3]).unwrap();
1124            let sum = list
1125                .iter()
1126                .rfold(0, |acc, v| acc + v.extract::<usize>().unwrap());
1127            assert_eq!(sum, 6);
1128        });
1129    }
1130
1131    #[test]
1132    fn test_iter_try_fold() {
1133        Python::with_gil(|py: Python<'_>| {
1134            let list = PyList::new(py, [1, 2, 3]).unwrap();
1135            let sum = list
1136                .iter()
1137                .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1138                .unwrap();
1139            assert_eq!(sum, 6);
1140
1141            let list = PyList::new(py, ["foo", "bar"]).unwrap();
1142            assert!(list
1143                .iter()
1144                .try_fold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1145                .is_err());
1146        });
1147    }
1148
1149    #[test]
1150    fn test_iter_try_rfold() {
1151        Python::with_gil(|py: Python<'_>| {
1152            let list = PyList::new(py, [1, 2, 3]).unwrap();
1153            let sum = list
1154                .iter()
1155                .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1156                .unwrap();
1157            assert_eq!(sum, 6);
1158
1159            let list = PyList::new(py, ["foo", "bar"]).unwrap();
1160            assert!(list
1161                .iter()
1162                .try_rfold(0, |acc, v| PyResult::Ok(acc + v.extract::<usize>()?))
1163                .is_err());
1164        });
1165    }
1166
1167    #[test]
1168    fn test_into_iter() {
1169        Python::with_gil(|py| {
1170            let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1171            for (i, item) in list.iter().enumerate() {
1172                assert_eq!((i + 1) as i32, item.extract::<i32>().unwrap());
1173            }
1174        });
1175    }
1176
1177    #[test]
1178    fn test_into_iter_bound() {
1179        use crate::types::any::PyAnyMethods;
1180
1181        Python::with_gil(|py| {
1182            let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1183            let mut items = vec![];
1184            for item in &list {
1185                items.push(item.extract::<i32>().unwrap());
1186            }
1187            assert_eq!(items, vec![1, 2, 3, 4]);
1188        });
1189    }
1190
1191    #[test]
1192    fn test_as_sequence() {
1193        Python::with_gil(|py| {
1194            let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1195
1196            assert_eq!(list.as_sequence().len().unwrap(), 4);
1197            assert_eq!(
1198                list.as_sequence()
1199                    .get_item(1)
1200                    .unwrap()
1201                    .extract::<i32>()
1202                    .unwrap(),
1203                2
1204            );
1205        });
1206    }
1207
1208    #[test]
1209    fn test_into_sequence() {
1210        Python::with_gil(|py| {
1211            let list = PyList::new(py, [1, 2, 3, 4]).unwrap();
1212
1213            let sequence = list.into_sequence();
1214
1215            assert_eq!(sequence.len().unwrap(), 4);
1216            assert_eq!(sequence.get_item(1).unwrap().extract::<i32>().unwrap(), 2);
1217        });
1218    }
1219
1220    #[test]
1221    fn test_extract() {
1222        Python::with_gil(|py| {
1223            let v = vec![2, 3, 5, 7];
1224            let list = PyList::new(py, &v).unwrap();
1225            let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
1226            assert_eq!(v, v2);
1227        });
1228    }
1229
1230    #[test]
1231    fn test_sort() {
1232        Python::with_gil(|py| {
1233            let v = vec![7, 3, 2, 5];
1234            let list = PyList::new(py, &v).unwrap();
1235            assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1236            assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1237            assert_eq!(2, list.get_item(2).unwrap().extract::<i32>().unwrap());
1238            assert_eq!(5, list.get_item(3).unwrap().extract::<i32>().unwrap());
1239            list.sort().unwrap();
1240            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1241            assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1242            assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1243            assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1244        });
1245    }
1246
1247    #[test]
1248    fn test_reverse() {
1249        Python::with_gil(|py| {
1250            let v = vec![2, 3, 5, 7];
1251            let list = PyList::new(py, &v).unwrap();
1252            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1253            assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap());
1254            assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap());
1255            assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap());
1256            list.reverse().unwrap();
1257            assert_eq!(7, list.get_item(0).unwrap().extract::<i32>().unwrap());
1258            assert_eq!(5, list.get_item(1).unwrap().extract::<i32>().unwrap());
1259            assert_eq!(3, list.get_item(2).unwrap().extract::<i32>().unwrap());
1260            assert_eq!(2, list.get_item(3).unwrap().extract::<i32>().unwrap());
1261        });
1262    }
1263
1264    #[test]
1265    fn test_array_into_pyobject() {
1266        Python::with_gil(|py| {
1267            let array = [1, 2].into_pyobject(py).unwrap();
1268            let list = array.downcast::<PyList>().unwrap();
1269            assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1270            assert_eq!(2, list.get_item(1).unwrap().extract::<i32>().unwrap());
1271        });
1272    }
1273
1274    #[test]
1275    fn test_list_get_item_invalid_index() {
1276        Python::with_gil(|py| {
1277            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1278            let obj = list.get_item(5);
1279            assert!(obj.is_err());
1280            assert_eq!(
1281                obj.unwrap_err().to_string(),
1282                "IndexError: list index out of range"
1283            );
1284        });
1285    }
1286
1287    #[test]
1288    fn test_list_get_item_sanity() {
1289        Python::with_gil(|py| {
1290            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1291            let obj = list.get_item(0);
1292            assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
1293        });
1294    }
1295
1296    #[cfg(not(Py_LIMITED_API))]
1297    #[test]
1298    fn test_list_get_item_unchecked_sanity() {
1299        Python::with_gil(|py| {
1300            let list = PyList::new(py, [2, 3, 5, 7]).unwrap();
1301            let obj = unsafe { list.get_item_unchecked(0) };
1302            assert_eq!(obj.extract::<i32>().unwrap(), 2);
1303        });
1304    }
1305
1306    #[test]
1307    fn test_list_del_item() {
1308        Python::with_gil(|py| {
1309            let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1310            assert!(list.del_item(10).is_err());
1311            assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1312            assert!(list.del_item(0).is_ok());
1313            assert_eq!(1, list.get_item(0).unwrap().extract::<i32>().unwrap());
1314            assert!(list.del_item(0).is_ok());
1315            assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap());
1316            assert!(list.del_item(0).is_ok());
1317            assert_eq!(3, list.get_item(0).unwrap().extract::<i32>().unwrap());
1318            assert!(list.del_item(0).is_ok());
1319            assert_eq!(5, list.get_item(0).unwrap().extract::<i32>().unwrap());
1320            assert!(list.del_item(0).is_ok());
1321            assert_eq!(8, list.get_item(0).unwrap().extract::<i32>().unwrap());
1322            assert!(list.del_item(0).is_ok());
1323            assert_eq!(0, list.len());
1324            assert!(list.del_item(0).is_err());
1325        });
1326    }
1327
1328    #[test]
1329    fn test_list_set_slice() {
1330        Python::with_gil(|py| {
1331            let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1332            let ins = PyList::new(py, [7, 4]).unwrap();
1333            list.set_slice(1, 4, &ins).unwrap();
1334            assert_eq!([1, 7, 4, 5, 8], list.extract::<[i32; 5]>().unwrap());
1335            list.set_slice(3, 100, &PyList::empty(py)).unwrap();
1336            assert_eq!([1, 7, 4], list.extract::<[i32; 3]>().unwrap());
1337        });
1338    }
1339
1340    #[test]
1341    fn test_list_del_slice() {
1342        Python::with_gil(|py| {
1343            let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1344            list.del_slice(1, 4).unwrap();
1345            assert_eq!([1, 5, 8], list.extract::<[i32; 3]>().unwrap());
1346            list.del_slice(1, 100).unwrap();
1347            assert_eq!([1], list.extract::<[i32; 1]>().unwrap());
1348        });
1349    }
1350
1351    #[test]
1352    fn test_list_contains() {
1353        Python::with_gil(|py| {
1354            let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1355            assert_eq!(6, list.len());
1356
1357            let bad_needle = 7i32.into_pyobject(py).unwrap();
1358            assert!(!list.contains(&bad_needle).unwrap());
1359
1360            let good_needle = 8i32.into_pyobject(py).unwrap();
1361            assert!(list.contains(&good_needle).unwrap());
1362
1363            let type_coerced_needle = 8f32.into_pyobject(py).unwrap();
1364            assert!(list.contains(&type_coerced_needle).unwrap());
1365        });
1366    }
1367
1368    #[test]
1369    fn test_list_index() {
1370        Python::with_gil(|py| {
1371            let list = PyList::new(py, [1, 1, 2, 3, 5, 8]).unwrap();
1372            assert_eq!(0, list.index(1i32).unwrap());
1373            assert_eq!(2, list.index(2i32).unwrap());
1374            assert_eq!(3, list.index(3i32).unwrap());
1375            assert_eq!(4, list.index(5i32).unwrap());
1376            assert_eq!(5, list.index(8i32).unwrap());
1377            assert!(list.index(42i32).is_err());
1378        });
1379    }
1380
1381    use std::ops::Range;
1382
1383    // An iterator that lies about its `ExactSizeIterator` implementation.
1384    // See https://github.com/PyO3/pyo3/issues/2118
1385    struct FaultyIter(Range<usize>, usize);
1386
1387    impl Iterator for FaultyIter {
1388        type Item = usize;
1389
1390        fn next(&mut self) -> Option<Self::Item> {
1391            self.0.next()
1392        }
1393    }
1394
1395    impl ExactSizeIterator for FaultyIter {
1396        fn len(&self) -> usize {
1397            self.1
1398        }
1399    }
1400
1401    #[test]
1402    #[should_panic(
1403        expected = "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation."
1404    )]
1405    fn too_long_iterator() {
1406        Python::with_gil(|py| {
1407            let iter = FaultyIter(0..usize::MAX, 73);
1408            let _list = PyList::new(py, iter).unwrap();
1409        })
1410    }
1411
1412    #[test]
1413    #[should_panic(
1414        expected = "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation."
1415    )]
1416    fn too_short_iterator() {
1417        Python::with_gil(|py| {
1418            let iter = FaultyIter(0..35, 73);
1419            let _list = PyList::new(py, iter).unwrap();
1420        })
1421    }
1422
1423    #[test]
1424    #[should_panic(
1425        expected = "out of range integral type conversion attempted on `elements.len()`"
1426    )]
1427    fn overflowing_size() {
1428        Python::with_gil(|py| {
1429            let iter = FaultyIter(0..0, usize::MAX);
1430
1431            let _list = PyList::new(py, iter).unwrap();
1432        })
1433    }
1434
1435    #[test]
1436    fn bad_intopyobject_doesnt_cause_leaks() {
1437        use crate::types::PyInt;
1438        use std::convert::Infallible;
1439        use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1440        static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0);
1441
1442        struct Bad(usize);
1443
1444        impl Drop for Bad {
1445            fn drop(&mut self) {
1446                NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst);
1447            }
1448        }
1449
1450        impl<'py> IntoPyObject<'py> for Bad {
1451            type Target = PyInt;
1452            type Output = crate::Bound<'py, Self::Target>;
1453            type Error = Infallible;
1454
1455            fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
1456                // This panic should not lead to a memory leak
1457                assert_ne!(self.0, 42);
1458                self.0.into_pyobject(py)
1459            }
1460        }
1461
1462        struct FaultyIter(Range<usize>, usize);
1463
1464        impl Iterator for FaultyIter {
1465            type Item = Bad;
1466
1467            fn next(&mut self) -> Option<Self::Item> {
1468                self.0.next().map(|i| {
1469                    NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst);
1470                    Bad(i)
1471                })
1472            }
1473        }
1474
1475        impl ExactSizeIterator for FaultyIter {
1476            fn len(&self) -> usize {
1477                self.1
1478            }
1479        }
1480
1481        Python::with_gil(|py| {
1482            std::panic::catch_unwind(|| {
1483                let iter = FaultyIter(0..50, 50);
1484                let _list = PyList::new(py, iter).unwrap();
1485            })
1486            .unwrap_err();
1487        });
1488
1489        assert_eq!(
1490            NEEDS_DESTRUCTING_COUNT.load(SeqCst),
1491            0,
1492            "Some destructors did not run"
1493        );
1494    }
1495
1496    #[test]
1497    fn test_list_to_tuple() {
1498        Python::with_gil(|py| {
1499            let list = PyList::new(py, vec![1, 2, 3]).unwrap();
1500            let tuple = list.to_tuple();
1501            let tuple_expected = PyTuple::new(py, vec![1, 2, 3]).unwrap();
1502            assert!(tuple.eq(tuple_expected).unwrap());
1503        })
1504    }
1505}