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