1 | use std::iter::FusedIterator; |
2 | |
3 | use crate::err::{self, PyResult}; |
4 | use crate::ffi::{self, Py_ssize_t}; |
5 | use crate::internal_tricks::get_ssize_index; |
6 | use crate::types::{PySequence, PyTuple}; |
7 | use crate::{Py, PyAny, PyObject, Python, ToPyObject}; |
8 | |
9 | /// Represents a Python `list`. |
10 | #[repr (transparent)] |
11 | pub struct PyList(PyAny); |
12 | |
13 | pyobject_native_type_core!(PyList, pyobject_native_static_type_object!(ffi::PyList_Type), #checkfunction=ffi::PyList_Check); |
14 | |
15 | #[inline ] |
16 | #[track_caller ] |
17 | pub(crate) fn new_from_iter( |
18 | py: Python<'_>, |
19 | elements: &mut dyn ExactSizeIterator<Item = PyObject>, |
20 | ) -> Py<PyList> { |
21 | unsafe { |
22 | // PyList_New checks for overflow but has a bad error message, so we check ourselves |
23 | let len: Py_ssize_t = elements |
24 | .len() |
25 | .try_into() |
26 | .expect("out of range integral type conversion attempted on `elements.len()`" ); |
27 | |
28 | let ptr = ffi::PyList_New(len); |
29 | |
30 | // We create the `Py` pointer here for two reasons: |
31 | // - panics if the ptr is null |
32 | // - its Drop cleans up the list if user code or the asserts panic. |
33 | let list: Py<PyList> = Py::from_owned_ptr(py, ptr); |
34 | |
35 | let mut counter: Py_ssize_t = 0; |
36 | |
37 | for obj in elements.take(len as usize) { |
38 | #[cfg (not(Py_LIMITED_API))] |
39 | ffi::PyList_SET_ITEM(ptr, counter, obj.into_ptr()); |
40 | #[cfg (Py_LIMITED_API)] |
41 | ffi::PyList_SetItem(ptr, counter, obj.into_ptr()); |
42 | counter += 1; |
43 | } |
44 | |
45 | assert!(elements.next().is_none(), "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation." ); |
46 | assert_eq!(len, counter, "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation." ); |
47 | |
48 | list |
49 | } |
50 | } |
51 | |
52 | impl PyList { |
53 | /// Constructs a new list with the given elements. |
54 | /// |
55 | /// If you want to create a [`PyList`] with elements of different or unknown types, or from an |
56 | /// iterable that doesn't implement [`ExactSizeIterator`], use [`PyList::append`]. |
57 | /// |
58 | /// # Examples |
59 | /// |
60 | /// ```rust |
61 | /// use pyo3::prelude::*; |
62 | /// use pyo3::types::PyList; |
63 | /// |
64 | /// # fn main() { |
65 | /// Python::with_gil(|py| { |
66 | /// let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5]; |
67 | /// let list: &PyList = PyList::new(py, elements); |
68 | /// assert_eq!(format!("{:?}" , list), "[0, 1, 2, 3, 4, 5]" ); |
69 | /// }); |
70 | /// # } |
71 | /// ``` |
72 | /// |
73 | /// # Panics |
74 | /// |
75 | /// This function will panic if `element`'s [`ExactSizeIterator`] implementation is incorrect. |
76 | /// All standard library structures implement this trait correctly, if they do, so calling this |
77 | /// function with (for example) [`Vec`]`<T>` or `&[T]` will always succeed. |
78 | #[track_caller ] |
79 | pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList |
80 | where |
81 | T: ToPyObject, |
82 | U: ExactSizeIterator<Item = T>, |
83 | { |
84 | let mut iter = elements.into_iter().map(|e| e.to_object(py)); |
85 | let list = new_from_iter(py, &mut iter); |
86 | list.into_ref(py) |
87 | } |
88 | |
89 | /// Constructs a new empty list. |
90 | pub fn empty(py: Python<'_>) -> &PyList { |
91 | unsafe { py.from_owned_ptr::<PyList>(ffi::PyList_New(0)) } |
92 | } |
93 | |
94 | /// Returns the length of the list. |
95 | pub fn len(&self) -> usize { |
96 | unsafe { |
97 | #[cfg (not(Py_LIMITED_API))] |
98 | let size = ffi::PyList_GET_SIZE(self.as_ptr()); |
99 | #[cfg (Py_LIMITED_API)] |
100 | let size = ffi::PyList_Size(self.as_ptr()); |
101 | |
102 | // non-negative Py_ssize_t should always fit into Rust usize |
103 | size as usize |
104 | } |
105 | } |
106 | |
107 | /// Checks if the list is empty. |
108 | pub fn is_empty(&self) -> bool { |
109 | self.len() == 0 |
110 | } |
111 | |
112 | /// Returns `self` cast as a `PySequence`. |
113 | pub fn as_sequence(&self) -> &PySequence { |
114 | unsafe { self.downcast_unchecked() } |
115 | } |
116 | |
117 | /// Gets the list item at the specified index. |
118 | /// # Example |
119 | /// ``` |
120 | /// use pyo3::{prelude::*, types::PyList}; |
121 | /// Python::with_gil(|py| { |
122 | /// let list = PyList::new(py, [2, 3, 5, 7]); |
123 | /// let obj = list.get_item(0); |
124 | /// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2); |
125 | /// }); |
126 | /// ``` |
127 | pub fn get_item(&self, index: usize) -> PyResult<&PyAny> { |
128 | unsafe { |
129 | let item = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t); |
130 | // PyList_GetItem return borrowed ptr; must make owned for safety (see #890). |
131 | ffi::Py_XINCREF(item); |
132 | self.py().from_owned_ptr_or_err(item) |
133 | } |
134 | } |
135 | |
136 | /// Gets the list item at the specified index. Undefined behavior on bad index. Use with caution. |
137 | /// |
138 | /// # Safety |
139 | /// |
140 | /// Caller must verify that the index is within the bounds of the list. |
141 | #[cfg (not(Py_LIMITED_API))] |
142 | pub unsafe fn get_item_unchecked(&self, index: usize) -> &PyAny { |
143 | let item = ffi::PyList_GET_ITEM(self.as_ptr(), index as Py_ssize_t); |
144 | // PyList_GET_ITEM return borrowed ptr; must make owned for safety (see #890). |
145 | ffi::Py_XINCREF(item); |
146 | self.py().from_owned_ptr(item) |
147 | } |
148 | |
149 | /// Takes the slice `self[low:high]` and returns it as a new list. |
150 | /// |
151 | /// Indices must be nonnegative, and out-of-range indices are clipped to |
152 | /// `self.len()`. |
153 | pub fn get_slice(&self, low: usize, high: usize) -> &PyList { |
154 | unsafe { |
155 | self.py().from_owned_ptr(ffi::PyList_GetSlice( |
156 | self.as_ptr(), |
157 | get_ssize_index(low), |
158 | get_ssize_index(high), |
159 | )) |
160 | } |
161 | } |
162 | |
163 | /// Sets the item at the specified index. |
164 | /// |
165 | /// Raises `IndexError` if the index is out of range. |
166 | pub fn set_item<I>(&self, index: usize, item: I) -> PyResult<()> |
167 | where |
168 | I: ToPyObject, |
169 | { |
170 | fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> { |
171 | err::error_on_minusone(list.py(), unsafe { |
172 | ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr()) |
173 | }) |
174 | } |
175 | |
176 | inner(self, index, item.to_object(self.py())) |
177 | } |
178 | |
179 | /// Deletes the `index`th element of self. |
180 | /// |
181 | /// This is equivalent to the Python statement `del self[i]`. |
182 | #[inline ] |
183 | pub fn del_item(&self, index: usize) -> PyResult<()> { |
184 | self.as_sequence().del_item(index) |
185 | } |
186 | |
187 | /// Assigns the sequence `seq` to the slice of `self` from `low` to `high`. |
188 | /// |
189 | /// This is equivalent to the Python statement `self[low:high] = v`. |
190 | #[inline ] |
191 | pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> { |
192 | err::error_on_minusone(self.py(), unsafe { |
193 | ffi::PyList_SetSlice( |
194 | self.as_ptr(), |
195 | get_ssize_index(low), |
196 | get_ssize_index(high), |
197 | seq.as_ptr(), |
198 | ) |
199 | }) |
200 | } |
201 | |
202 | /// Deletes the slice from `low` to `high` from `self`. |
203 | /// |
204 | /// This is equivalent to the Python statement `del self[low:high]`. |
205 | #[inline ] |
206 | pub fn del_slice(&self, low: usize, high: usize) -> PyResult<()> { |
207 | self.as_sequence().del_slice(low, high) |
208 | } |
209 | |
210 | /// Appends an item to the list. |
211 | pub fn append<I>(&self, item: I) -> PyResult<()> |
212 | where |
213 | I: ToPyObject, |
214 | { |
215 | fn inner(list: &PyList, item: PyObject) -> PyResult<()> { |
216 | err::error_on_minusone(list.py(), unsafe { |
217 | ffi::PyList_Append(list.as_ptr(), item.as_ptr()) |
218 | }) |
219 | } |
220 | |
221 | inner(self, item.to_object(self.py())) |
222 | } |
223 | |
224 | /// Inserts an item at the specified index. |
225 | /// |
226 | /// If `index >= self.len()`, inserts at the end. |
227 | pub fn insert<I>(&self, index: usize, item: I) -> PyResult<()> |
228 | where |
229 | I: ToPyObject, |
230 | { |
231 | fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> { |
232 | err::error_on_minusone(list.py(), unsafe { |
233 | ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr()) |
234 | }) |
235 | } |
236 | |
237 | inner(self, index, item.to_object(self.py())) |
238 | } |
239 | |
240 | /// Determines if self contains `value`. |
241 | /// |
242 | /// This is equivalent to the Python expression `value in self`. |
243 | #[inline ] |
244 | pub fn contains<V>(&self, value: V) -> PyResult<bool> |
245 | where |
246 | V: ToPyObject, |
247 | { |
248 | self.as_sequence().contains(value) |
249 | } |
250 | |
251 | /// Returns the first index `i` for which `self[i] == value`. |
252 | /// |
253 | /// This is equivalent to the Python expression `self.index(value)`. |
254 | #[inline ] |
255 | pub fn index<V>(&self, value: V) -> PyResult<usize> |
256 | where |
257 | V: ToPyObject, |
258 | { |
259 | self.as_sequence().index(value) |
260 | } |
261 | |
262 | /// Returns an iterator over this list's items. |
263 | pub fn iter(&self) -> PyListIterator<'_> { |
264 | PyListIterator { |
265 | list: self, |
266 | index: 0, |
267 | length: self.len(), |
268 | } |
269 | } |
270 | |
271 | /// Sorts the list in-place. Equivalent to the Python expression `l.sort()`. |
272 | pub fn sort(&self) -> PyResult<()> { |
273 | err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) }) |
274 | } |
275 | |
276 | /// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`. |
277 | pub fn reverse(&self) -> PyResult<()> { |
278 | err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) }) |
279 | } |
280 | |
281 | /// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`. |
282 | /// |
283 | /// This method is equivalent to `self.as_sequence().to_tuple()` and faster than `PyTuple::new(py, this_list)`. |
284 | pub fn to_tuple(&self) -> &PyTuple { |
285 | unsafe { self.py().from_owned_ptr(ffi::PyList_AsTuple(self.as_ptr())) } |
286 | } |
287 | } |
288 | |
289 | index_impls!(PyList, "list" , PyList::len, PyList::get_slice); |
290 | |
291 | /// Used by `PyList::iter()`. |
292 | pub struct PyListIterator<'a> { |
293 | list: &'a PyList, |
294 | index: usize, |
295 | length: usize, |
296 | } |
297 | |
298 | impl<'a> PyListIterator<'a> { |
299 | unsafe fn get_item(&self, index: usize) -> &'a PyAny { |
300 | #[cfg (any(Py_LIMITED_API, PyPy))] |
301 | let item = self.list.get_item(index).expect("list.get failed" ); |
302 | #[cfg (not(any(Py_LIMITED_API, PyPy)))] |
303 | let item: &PyAny = self.list.get_item_unchecked(index); |
304 | item |
305 | } |
306 | } |
307 | |
308 | impl<'a> Iterator for PyListIterator<'a> { |
309 | type Item = &'a PyAny; |
310 | |
311 | #[inline ] |
312 | fn next(&mut self) -> Option<Self::Item> { |
313 | let length: usize = self.length.min(self.list.len()); |
314 | |
315 | if self.index < length { |
316 | let item: &PyAny = unsafe { self.get_item(self.index) }; |
317 | self.index += 1; |
318 | Some(item) |
319 | } else { |
320 | None |
321 | } |
322 | } |
323 | |
324 | #[inline ] |
325 | fn size_hint(&self) -> (usize, Option<usize>) { |
326 | let len: usize = self.len(); |
327 | (len, Some(len)) |
328 | } |
329 | } |
330 | |
331 | impl<'a> DoubleEndedIterator for PyListIterator<'a> { |
332 | #[inline ] |
333 | fn next_back(&mut self) -> Option<Self::Item> { |
334 | let length: usize = self.length.min(self.list.len()); |
335 | |
336 | if self.index < length { |
337 | let item: &PyAny = unsafe { self.get_item(index:length - 1) }; |
338 | self.length = length - 1; |
339 | Some(item) |
340 | } else { |
341 | None |
342 | } |
343 | } |
344 | } |
345 | |
346 | impl<'a> ExactSizeIterator for PyListIterator<'a> { |
347 | fn len(&self) -> usize { |
348 | self.length.saturating_sub(self.index) |
349 | } |
350 | } |
351 | |
352 | impl FusedIterator for PyListIterator<'_> {} |
353 | |
354 | impl<'a> IntoIterator for &'a PyList { |
355 | type Item = &'a PyAny; |
356 | type IntoIter = PyListIterator<'a>; |
357 | |
358 | fn into_iter(self) -> Self::IntoIter { |
359 | self.iter() |
360 | } |
361 | } |
362 | |
363 | #[cfg (test)] |
364 | mod tests { |
365 | use crate::types::{PyList, PyTuple}; |
366 | use crate::Python; |
367 | use crate::{IntoPy, PyObject, ToPyObject}; |
368 | |
369 | #[test ] |
370 | fn test_new() { |
371 | Python::with_gil(|py| { |
372 | let list = PyList::new(py, [2, 3, 5, 7]); |
373 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
374 | assert_eq!(3, list[1].extract::<i32>().unwrap()); |
375 | assert_eq!(5, list[2].extract::<i32>().unwrap()); |
376 | assert_eq!(7, list[3].extract::<i32>().unwrap()); |
377 | }); |
378 | } |
379 | |
380 | #[test ] |
381 | fn test_len() { |
382 | Python::with_gil(|py| { |
383 | let list = PyList::new(py, [1, 2, 3, 4]); |
384 | assert_eq!(4, list.len()); |
385 | }); |
386 | } |
387 | |
388 | #[test ] |
389 | fn test_get_item() { |
390 | Python::with_gil(|py| { |
391 | let list = PyList::new(py, [2, 3, 5, 7]); |
392 | assert_eq!(2, list.get_item(0).unwrap().extract::<i32>().unwrap()); |
393 | assert_eq!(3, list.get_item(1).unwrap().extract::<i32>().unwrap()); |
394 | assert_eq!(5, list.get_item(2).unwrap().extract::<i32>().unwrap()); |
395 | assert_eq!(7, list.get_item(3).unwrap().extract::<i32>().unwrap()); |
396 | }); |
397 | } |
398 | |
399 | #[test ] |
400 | fn test_get_slice() { |
401 | Python::with_gil(|py| { |
402 | let list = PyList::new(py, [2, 3, 5, 7]); |
403 | let slice = list.get_slice(1, 3); |
404 | assert_eq!(2, slice.len()); |
405 | let slice = list.get_slice(1, 7); |
406 | assert_eq!(3, slice.len()); |
407 | }); |
408 | } |
409 | |
410 | #[test ] |
411 | fn test_set_item() { |
412 | Python::with_gil(|py| { |
413 | let list = PyList::new(py, [2, 3, 5, 7]); |
414 | let val = 42i32.to_object(py); |
415 | let val2 = 42i32.to_object(py); |
416 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
417 | list.set_item(0, val).unwrap(); |
418 | assert_eq!(42, list[0].extract::<i32>().unwrap()); |
419 | assert!(list.set_item(10, val2).is_err()); |
420 | }); |
421 | } |
422 | |
423 | #[test ] |
424 | fn test_set_item_refcnt() { |
425 | Python::with_gil(|py| { |
426 | let obj = py.eval("object()" , None, None).unwrap(); |
427 | let cnt; |
428 | { |
429 | let _pool = unsafe { crate::GILPool::new() }; |
430 | let v = vec![2]; |
431 | let ob = v.to_object(py); |
432 | let list: &PyList = ob.downcast(py).unwrap(); |
433 | cnt = obj.get_refcnt(); |
434 | list.set_item(0, obj).unwrap(); |
435 | } |
436 | |
437 | assert_eq!(cnt, obj.get_refcnt()); |
438 | }); |
439 | } |
440 | |
441 | #[test ] |
442 | fn test_insert() { |
443 | Python::with_gil(|py| { |
444 | let list = PyList::new(py, [2, 3, 5, 7]); |
445 | let val = 42i32.to_object(py); |
446 | let val2 = 43i32.to_object(py); |
447 | assert_eq!(4, list.len()); |
448 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
449 | list.insert(0, val).unwrap(); |
450 | list.insert(1000, val2).unwrap(); |
451 | assert_eq!(6, list.len()); |
452 | assert_eq!(42, list[0].extract::<i32>().unwrap()); |
453 | assert_eq!(2, list[1].extract::<i32>().unwrap()); |
454 | assert_eq!(43, list[5].extract::<i32>().unwrap()); |
455 | }); |
456 | } |
457 | |
458 | #[test ] |
459 | fn test_insert_refcnt() { |
460 | Python::with_gil(|py| { |
461 | let cnt; |
462 | let obj = py.eval("object()" , None, None).unwrap(); |
463 | { |
464 | let _pool = unsafe { crate::GILPool::new() }; |
465 | let list = PyList::empty(py); |
466 | cnt = obj.get_refcnt(); |
467 | list.insert(0, obj).unwrap(); |
468 | } |
469 | |
470 | assert_eq!(cnt, obj.get_refcnt()); |
471 | }); |
472 | } |
473 | |
474 | #[test ] |
475 | fn test_append() { |
476 | Python::with_gil(|py| { |
477 | let list = PyList::new(py, [2]); |
478 | list.append(3).unwrap(); |
479 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
480 | assert_eq!(3, list[1].extract::<i32>().unwrap()); |
481 | }); |
482 | } |
483 | |
484 | #[test ] |
485 | fn test_append_refcnt() { |
486 | Python::with_gil(|py| { |
487 | let cnt; |
488 | let obj = py.eval("object()" , None, None).unwrap(); |
489 | { |
490 | let _pool = unsafe { crate::GILPool::new() }; |
491 | let list = PyList::empty(py); |
492 | cnt = obj.get_refcnt(); |
493 | list.append(obj).unwrap(); |
494 | } |
495 | assert_eq!(cnt, obj.get_refcnt()); |
496 | }); |
497 | } |
498 | |
499 | #[test ] |
500 | fn test_iter() { |
501 | Python::with_gil(|py| { |
502 | let v = vec![2, 3, 5, 7]; |
503 | let list = PyList::new(py, &v); |
504 | let mut idx = 0; |
505 | for el in list { |
506 | assert_eq!(v[idx], el.extract::<i32>().unwrap()); |
507 | idx += 1; |
508 | } |
509 | assert_eq!(idx, v.len()); |
510 | }); |
511 | } |
512 | |
513 | #[test ] |
514 | fn test_iter_size_hint() { |
515 | Python::with_gil(|py| { |
516 | let v = vec![2, 3, 5, 7]; |
517 | let ob = v.to_object(py); |
518 | let list: &PyList = ob.downcast(py).unwrap(); |
519 | |
520 | let mut iter = list.iter(); |
521 | assert_eq!(iter.size_hint(), (v.len(), Some(v.len()))); |
522 | iter.next(); |
523 | assert_eq!(iter.size_hint(), (v.len() - 1, Some(v.len() - 1))); |
524 | |
525 | // Exhaust iterator. |
526 | for _ in &mut iter {} |
527 | |
528 | assert_eq!(iter.size_hint(), (0, Some(0))); |
529 | }); |
530 | } |
531 | |
532 | #[test ] |
533 | fn test_iter_rev() { |
534 | Python::with_gil(|py| { |
535 | let v = vec![2, 3, 5, 7]; |
536 | let ob = v.to_object(py); |
537 | let list: &PyList = ob.downcast(py).unwrap(); |
538 | |
539 | let mut iter = list.iter().rev(); |
540 | |
541 | assert_eq!(iter.size_hint(), (4, Some(4))); |
542 | |
543 | assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 7); |
544 | assert_eq!(iter.size_hint(), (3, Some(3))); |
545 | |
546 | assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 5); |
547 | assert_eq!(iter.size_hint(), (2, Some(2))); |
548 | |
549 | assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3); |
550 | assert_eq!(iter.size_hint(), (1, Some(1))); |
551 | |
552 | assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 2); |
553 | assert_eq!(iter.size_hint(), (0, Some(0))); |
554 | |
555 | assert!(iter.next().is_none()); |
556 | assert!(iter.next().is_none()); |
557 | }); |
558 | } |
559 | |
560 | #[test ] |
561 | fn test_into_iter() { |
562 | Python::with_gil(|py| { |
563 | let list = PyList::new(py, [1, 2, 3, 4]); |
564 | for (i, item) in list.iter().enumerate() { |
565 | assert_eq!((i + 1) as i32, item.extract::<i32>().unwrap()); |
566 | } |
567 | }); |
568 | } |
569 | |
570 | #[test ] |
571 | fn test_extract() { |
572 | Python::with_gil(|py| { |
573 | let v = vec![2, 3, 5, 7]; |
574 | let list = PyList::new(py, &v); |
575 | let v2 = list.as_ref().extract::<Vec<i32>>().unwrap(); |
576 | assert_eq!(v, v2); |
577 | }); |
578 | } |
579 | |
580 | #[test ] |
581 | fn test_sort() { |
582 | Python::with_gil(|py| { |
583 | let v = vec![7, 3, 2, 5]; |
584 | let list = PyList::new(py, &v); |
585 | assert_eq!(7, list[0].extract::<i32>().unwrap()); |
586 | assert_eq!(3, list[1].extract::<i32>().unwrap()); |
587 | assert_eq!(2, list[2].extract::<i32>().unwrap()); |
588 | assert_eq!(5, list[3].extract::<i32>().unwrap()); |
589 | list.sort().unwrap(); |
590 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
591 | assert_eq!(3, list[1].extract::<i32>().unwrap()); |
592 | assert_eq!(5, list[2].extract::<i32>().unwrap()); |
593 | assert_eq!(7, list[3].extract::<i32>().unwrap()); |
594 | }); |
595 | } |
596 | |
597 | #[test ] |
598 | fn test_reverse() { |
599 | Python::with_gil(|py| { |
600 | let v = vec![2, 3, 5, 7]; |
601 | let list = PyList::new(py, &v); |
602 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
603 | assert_eq!(3, list[1].extract::<i32>().unwrap()); |
604 | assert_eq!(5, list[2].extract::<i32>().unwrap()); |
605 | assert_eq!(7, list[3].extract::<i32>().unwrap()); |
606 | list.reverse().unwrap(); |
607 | assert_eq!(7, list[0].extract::<i32>().unwrap()); |
608 | assert_eq!(5, list[1].extract::<i32>().unwrap()); |
609 | assert_eq!(3, list[2].extract::<i32>().unwrap()); |
610 | assert_eq!(2, list[3].extract::<i32>().unwrap()); |
611 | }); |
612 | } |
613 | |
614 | #[test ] |
615 | fn test_array_into_py() { |
616 | Python::with_gil(|py| { |
617 | let array: PyObject = [1, 2].into_py(py); |
618 | let list: &PyList = array.downcast(py).unwrap(); |
619 | assert_eq!(1, list[0].extract::<i32>().unwrap()); |
620 | assert_eq!(2, list[1].extract::<i32>().unwrap()); |
621 | }); |
622 | } |
623 | |
624 | #[test ] |
625 | fn test_list_get_item_invalid_index() { |
626 | Python::with_gil(|py| { |
627 | let list = PyList::new(py, [2, 3, 5, 7]); |
628 | let obj = list.get_item(5); |
629 | assert!(obj.is_err()); |
630 | assert_eq!( |
631 | obj.unwrap_err().to_string(), |
632 | "IndexError: list index out of range" |
633 | ); |
634 | }); |
635 | } |
636 | |
637 | #[test ] |
638 | fn test_list_get_item_sanity() { |
639 | Python::with_gil(|py| { |
640 | let list = PyList::new(py, [2, 3, 5, 7]); |
641 | let obj = list.get_item(0); |
642 | assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2); |
643 | }); |
644 | } |
645 | |
646 | #[cfg (not(any(Py_LIMITED_API, PyPy)))] |
647 | #[test ] |
648 | fn test_list_get_item_unchecked_sanity() { |
649 | Python::with_gil(|py| { |
650 | let list = PyList::new(py, [2, 3, 5, 7]); |
651 | let obj = unsafe { list.get_item_unchecked(0) }; |
652 | assert_eq!(obj.extract::<i32>().unwrap(), 2); |
653 | }); |
654 | } |
655 | |
656 | #[test ] |
657 | fn test_list_index_trait() { |
658 | Python::with_gil(|py| { |
659 | let list = PyList::new(py, [2, 3, 5]); |
660 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
661 | assert_eq!(3, list[1].extract::<i32>().unwrap()); |
662 | assert_eq!(5, list[2].extract::<i32>().unwrap()); |
663 | }); |
664 | } |
665 | |
666 | #[test ] |
667 | #[should_panic ] |
668 | fn test_list_index_trait_panic() { |
669 | Python::with_gil(|py| { |
670 | let list = PyList::new(py, [2, 3, 5]); |
671 | let _ = &list[7]; |
672 | }); |
673 | } |
674 | |
675 | #[test ] |
676 | fn test_list_index_trait_ranges() { |
677 | Python::with_gil(|py| { |
678 | let list = PyList::new(py, [2, 3, 5]); |
679 | assert_eq!(vec![3, 5], list[1..3].extract::<Vec<i32>>().unwrap()); |
680 | assert_eq!(Vec::<i32>::new(), list[3..3].extract::<Vec<i32>>().unwrap()); |
681 | assert_eq!(vec![3, 5], list[1..].extract::<Vec<i32>>().unwrap()); |
682 | assert_eq!(Vec::<i32>::new(), list[3..].extract::<Vec<i32>>().unwrap()); |
683 | assert_eq!(vec![2, 3, 5], list[..].extract::<Vec<i32>>().unwrap()); |
684 | assert_eq!(vec![3, 5], list[1..=2].extract::<Vec<i32>>().unwrap()); |
685 | assert_eq!(vec![2, 3], list[..2].extract::<Vec<i32>>().unwrap()); |
686 | assert_eq!(vec![2, 3], list[..=1].extract::<Vec<i32>>().unwrap()); |
687 | }) |
688 | } |
689 | |
690 | #[test ] |
691 | #[should_panic = "range start index 5 out of range for list of length 3" ] |
692 | fn test_list_index_trait_range_panic_start() { |
693 | Python::with_gil(|py| { |
694 | let list = PyList::new(py, [2, 3, 5]); |
695 | list[5..10].extract::<Vec<i32>>().unwrap(); |
696 | }) |
697 | } |
698 | |
699 | #[test ] |
700 | #[should_panic = "range end index 10 out of range for list of length 3" ] |
701 | fn test_list_index_trait_range_panic_end() { |
702 | Python::with_gil(|py| { |
703 | let list = PyList::new(py, [2, 3, 5]); |
704 | list[1..10].extract::<Vec<i32>>().unwrap(); |
705 | }) |
706 | } |
707 | |
708 | #[test ] |
709 | #[should_panic = "slice index starts at 2 but ends at 1" ] |
710 | fn test_list_index_trait_range_panic_wrong_order() { |
711 | Python::with_gil(|py| { |
712 | let list = PyList::new(py, [2, 3, 5]); |
713 | #[allow (clippy::reversed_empty_ranges)] |
714 | list[2..1].extract::<Vec<i32>>().unwrap(); |
715 | }) |
716 | } |
717 | |
718 | #[test ] |
719 | #[should_panic = "range start index 8 out of range for list of length 3" ] |
720 | fn test_list_index_trait_range_from_panic() { |
721 | Python::with_gil(|py| { |
722 | let list = PyList::new(py, [2, 3, 5]); |
723 | list[8..].extract::<Vec<i32>>().unwrap(); |
724 | }) |
725 | } |
726 | |
727 | #[test ] |
728 | fn test_list_del_item() { |
729 | Python::with_gil(|py| { |
730 | let list = PyList::new(py, [1, 1, 2, 3, 5, 8]); |
731 | assert!(list.del_item(10).is_err()); |
732 | assert_eq!(1, list[0].extract::<i32>().unwrap()); |
733 | assert!(list.del_item(0).is_ok()); |
734 | assert_eq!(1, list[0].extract::<i32>().unwrap()); |
735 | assert!(list.del_item(0).is_ok()); |
736 | assert_eq!(2, list[0].extract::<i32>().unwrap()); |
737 | assert!(list.del_item(0).is_ok()); |
738 | assert_eq!(3, list[0].extract::<i32>().unwrap()); |
739 | assert!(list.del_item(0).is_ok()); |
740 | assert_eq!(5, list[0].extract::<i32>().unwrap()); |
741 | assert!(list.del_item(0).is_ok()); |
742 | assert_eq!(8, list[0].extract::<i32>().unwrap()); |
743 | assert!(list.del_item(0).is_ok()); |
744 | assert_eq!(0, list.len()); |
745 | assert!(list.del_item(0).is_err()); |
746 | }); |
747 | } |
748 | |
749 | #[test ] |
750 | fn test_list_set_slice() { |
751 | Python::with_gil(|py| { |
752 | let list = PyList::new(py, [1, 1, 2, 3, 5, 8]); |
753 | let ins = PyList::new(py, [7, 4]); |
754 | list.set_slice(1, 4, ins).unwrap(); |
755 | assert_eq!([1, 7, 4, 5, 8], list.extract::<[i32; 5]>().unwrap()); |
756 | list.set_slice(3, 100, PyList::empty(py)).unwrap(); |
757 | assert_eq!([1, 7, 4], list.extract::<[i32; 3]>().unwrap()); |
758 | }); |
759 | } |
760 | |
761 | #[test ] |
762 | fn test_list_del_slice() { |
763 | Python::with_gil(|py| { |
764 | let list = PyList::new(py, [1, 1, 2, 3, 5, 8]); |
765 | list.del_slice(1, 4).unwrap(); |
766 | assert_eq!([1, 5, 8], list.extract::<[i32; 3]>().unwrap()); |
767 | list.del_slice(1, 100).unwrap(); |
768 | assert_eq!([1], list.extract::<[i32; 1]>().unwrap()); |
769 | }); |
770 | } |
771 | |
772 | #[test ] |
773 | fn test_list_contains() { |
774 | Python::with_gil(|py| { |
775 | let list = PyList::new(py, [1, 1, 2, 3, 5, 8]); |
776 | assert_eq!(6, list.len()); |
777 | |
778 | let bad_needle = 7i32.to_object(py); |
779 | assert!(!list.contains(&bad_needle).unwrap()); |
780 | |
781 | let good_needle = 8i32.to_object(py); |
782 | assert!(list.contains(&good_needle).unwrap()); |
783 | |
784 | let type_coerced_needle = 8f32.to_object(py); |
785 | assert!(list.contains(&type_coerced_needle).unwrap()); |
786 | }); |
787 | } |
788 | |
789 | #[test ] |
790 | fn test_list_index() { |
791 | Python::with_gil(|py| { |
792 | let list = PyList::new(py, [1, 1, 2, 3, 5, 8]); |
793 | assert_eq!(0, list.index(1i32).unwrap()); |
794 | assert_eq!(2, list.index(2i32).unwrap()); |
795 | assert_eq!(3, list.index(3i32).unwrap()); |
796 | assert_eq!(4, list.index(5i32).unwrap()); |
797 | assert_eq!(5, list.index(8i32).unwrap()); |
798 | assert!(list.index(42i32).is_err()); |
799 | }); |
800 | } |
801 | |
802 | use std::ops::Range; |
803 | |
804 | // An iterator that lies about its `ExactSizeIterator` implementation. |
805 | // See https://github.com/PyO3/pyo3/issues/2118 |
806 | struct FaultyIter(Range<usize>, usize); |
807 | |
808 | impl Iterator for FaultyIter { |
809 | type Item = usize; |
810 | |
811 | fn next(&mut self) -> Option<Self::Item> { |
812 | self.0.next() |
813 | } |
814 | } |
815 | |
816 | impl ExactSizeIterator for FaultyIter { |
817 | fn len(&self) -> usize { |
818 | self.1 |
819 | } |
820 | } |
821 | |
822 | #[test ] |
823 | #[should_panic ( |
824 | expected = "Attempted to create PyList but `elements` was larger than reported by its `ExactSizeIterator` implementation." |
825 | )] |
826 | fn too_long_iterator() { |
827 | Python::with_gil(|py| { |
828 | let iter = FaultyIter(0..usize::MAX, 73); |
829 | let _list = PyList::new(py, iter); |
830 | }) |
831 | } |
832 | |
833 | #[test ] |
834 | #[should_panic ( |
835 | expected = "Attempted to create PyList but `elements` was smaller than reported by its `ExactSizeIterator` implementation." |
836 | )] |
837 | fn too_short_iterator() { |
838 | Python::with_gil(|py| { |
839 | let iter = FaultyIter(0..35, 73); |
840 | let _list = PyList::new(py, iter); |
841 | }) |
842 | } |
843 | |
844 | #[test ] |
845 | #[should_panic ( |
846 | expected = "out of range integral type conversion attempted on `elements.len()`" |
847 | )] |
848 | fn overflowing_size() { |
849 | Python::with_gil(|py| { |
850 | let iter = FaultyIter(0..0, usize::MAX); |
851 | |
852 | let _list = PyList::new(py, iter); |
853 | }) |
854 | } |
855 | |
856 | #[cfg (feature = "macros" )] |
857 | #[test ] |
858 | fn bad_clone_mem_leaks() { |
859 | use crate::{Py, PyAny}; |
860 | use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; |
861 | static NEEDS_DESTRUCTING_COUNT: AtomicUsize = AtomicUsize::new(0); |
862 | |
863 | #[crate::pyclass ] |
864 | #[pyo3(crate = "crate" )] |
865 | struct Bad(usize); |
866 | |
867 | impl Clone for Bad { |
868 | fn clone(&self) -> Self { |
869 | // This panic should not lead to a memory leak |
870 | assert_ne!(self.0, 42); |
871 | NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst); |
872 | |
873 | Bad(self.0) |
874 | } |
875 | } |
876 | |
877 | impl Drop for Bad { |
878 | fn drop(&mut self) { |
879 | NEEDS_DESTRUCTING_COUNT.fetch_sub(1, SeqCst); |
880 | } |
881 | } |
882 | |
883 | impl ToPyObject for Bad { |
884 | fn to_object(&self, py: Python<'_>) -> Py<PyAny> { |
885 | self.to_owned().into_py(py) |
886 | } |
887 | } |
888 | |
889 | struct FaultyIter(Range<usize>, usize); |
890 | |
891 | impl Iterator for FaultyIter { |
892 | type Item = Bad; |
893 | |
894 | fn next(&mut self) -> Option<Self::Item> { |
895 | self.0.next().map(|i| { |
896 | NEEDS_DESTRUCTING_COUNT.fetch_add(1, SeqCst); |
897 | Bad(i) |
898 | }) |
899 | } |
900 | } |
901 | |
902 | impl ExactSizeIterator for FaultyIter { |
903 | fn len(&self) -> usize { |
904 | self.1 |
905 | } |
906 | } |
907 | |
908 | Python::with_gil(|py| { |
909 | std::panic::catch_unwind(|| { |
910 | let iter = FaultyIter(0..50, 50); |
911 | let _list = PyList::new(py, iter); |
912 | }) |
913 | .unwrap_err(); |
914 | }); |
915 | |
916 | assert_eq!( |
917 | NEEDS_DESTRUCTING_COUNT.load(SeqCst), |
918 | 0, |
919 | "Some destructors did not run" |
920 | ); |
921 | } |
922 | |
923 | #[test ] |
924 | fn test_list_to_tuple() { |
925 | Python::with_gil(|py| { |
926 | let list = PyList::new(py, vec![1, 2, 3]); |
927 | let tuple = list.to_tuple(); |
928 | let tuple_expected = PyTuple::new(py, vec![1, 2, 3]); |
929 | assert!(tuple.eq(tuple_expected).unwrap()); |
930 | }) |
931 | } |
932 | } |
933 | |