1use super::{
2 PositionIterInternal, PyGenericAlias, PyTupleRef, PyType, PyTypeRef,
3 iter::{builtins_iter, builtins_reversed},
4};
5use crate::atomic_func;
6use crate::common::lock::{
7 PyMappedRwLockReadGuard, PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard,
8};
9use crate::object::{Traverse, TraverseFn};
10use crate::{
11 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
12 builtins::PyStr,
13 class::PyClassImpl,
14 convert::ToPyObject,
15 function::{ArgSize, FuncArgs, OptionalArg, PyComparisonValue},
16 iter::PyExactSizeIterator,
17 protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
18 recursion::ReprGuard,
19 sequence::{MutObjectSequenceOp, OptionalRangeArgs, SequenceExt, SequenceMutExt},
20 sliceable::{SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp},
21 types::{
22 AsMapping, AsSequence, Comparable, Constructor, Initializer, IterNext, Iterable,
23 PyComparisonOp, Representable, SelfIter,
24 },
25 vm::VirtualMachine,
26};
27use rustpython_common::wtf8::Wtf8Buf;
28
29use alloc::fmt;
30use core::cell::Cell;
31use core::ops::DerefMut;
32use core::ptr::NonNull;
33use core::sync::atomic::{AtomicU32, Ordering};
34
35#[pyclass(module = false, name = "list", unhashable = true, traverse = "manual")]
36#[derive(Default)]
37pub struct PyList {
38 elements: PyRwLock<Vec<PyObjectRef>>,
39 mutation_counter: AtomicU32,
40}
41
42impl fmt::Debug for PyList {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.write_str("list")
46 }
47}
48
49impl From<Vec<PyObjectRef>> for PyList {
50 fn from(elements: Vec<PyObjectRef>) -> Self {
51 Self {
52 elements: PyRwLock::new(elements),
53 mutation_counter: AtomicU32::new(0),
54 }
55 }
56}
57
58impl FromIterator<PyObjectRef> for PyList {
59 fn from_iter<T: IntoIterator<Item = PyObjectRef>>(iter: T) -> Self {
60 Vec::from_iter(iter).into()
61 }
62}
63
64unsafe impl Traverse for PyList {
66 fn traverse(&self, traverse_fn: &mut TraverseFn<'_>) {
67 self.elements.traverse(traverse_fn);
68 }
69
70 fn clear(&mut self, out: &mut Vec<PyObjectRef>) {
71 if let Some(mut guard) = self.elements.try_write() {
75 out.extend(guard.drain(..));
76 }
77 }
78}
79
80thread_local! {
81 static LIST_FREELIST: Cell<crate::object::FreeList<PyList>> = const { Cell::new(crate::object::FreeList::new()) };
82}
83
84impl PyPayload for PyList {
85 const MAX_FREELIST: usize = 80;
86 const HAS_FREELIST: bool = true;
87
88 #[inline]
89 fn class(ctx: &Context) -> &'static Py<PyType> {
90 ctx.types.list_type
91 }
92
93 #[inline]
94 unsafe fn freelist_push(obj: *mut PyObject) -> bool {
95 LIST_FREELIST
96 .try_with(|fl| {
97 let mut list = fl.take();
98 let stored = if list.len() < Self::MAX_FREELIST {
99 list.push(obj);
100 true
101 } else {
102 false
103 };
104 fl.set(list);
105 stored
106 })
107 .unwrap_or(false)
108 }
109
110 #[inline]
111 unsafe fn freelist_pop(_payload: &Self) -> Option<NonNull<PyObject>> {
112 LIST_FREELIST
113 .try_with(|fl| {
114 let mut list = fl.take();
115 let result = list.pop().map(|p| unsafe { NonNull::new_unchecked(p) });
116 fl.set(list);
117 result
118 })
119 .ok()
120 .flatten()
121 }
122}
123
124impl ToPyObject for Vec<PyObjectRef> {
125 fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
126 PyList::from(self).into_ref(&vm.ctx).into()
127 }
128}
129
130impl PyList {
131 #[deprecated(note = "use PyList::from(...).into_ref() instead")]
132 pub fn new_ref(elements: Vec<PyObjectRef>, ctx: &Context) -> PyRef<Self> {
133 Self::from(elements).into_ref(ctx)
134 }
135
136 pub fn borrow_vec(&self) -> PyMappedRwLockReadGuard<'_, [PyObjectRef]> {
137 PyRwLockReadGuard::map(self.elements.read(), |v| &**v)
138 }
139
140 pub fn borrow_vec_mut(&self) -> PyRwLockWriteGuard<'_, Vec<PyObjectRef>> {
141 let guard = self.elements.write();
142 self.mutation_counter.fetch_add(1, Ordering::Relaxed);
143 guard
144 }
145
146 fn repeat(&self, n: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
147 let elements = &*self.borrow_vec();
148 let v = elements.mul(vm, n)?;
149 Ok(Self::from(v).into_ref(&vm.ctx))
150 }
151
152 fn irepeat(zelf: PyRef<Self>, n: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
153 zelf.borrow_vec_mut().imul(vm, n)?;
154 Ok(zelf)
155 }
156}
157
158#[derive(FromArgs, Default, Traverse)]
159pub(crate) struct SortOptions {
160 #[pyarg(named, default)]
161 key: Option<PyObjectRef>,
162 #[pytraverse(skip)]
163 #[pyarg(named, default = false)]
164 reverse: bool,
165}
166
167pub type PyListRef = PyRef<PyList>;
168
169#[pyclass(
170 with(
171 Constructor,
172 Initializer,
173 AsMapping,
174 Iterable,
175 Comparable,
176 AsSequence,
177 Representable
178 ),
179 flags(BASETYPE, SEQUENCE, _MATCH_SELF)
180)]
181impl PyList {
182 #[pymethod]
183 pub(crate) fn append(&self, x: PyObjectRef) {
184 self.borrow_vec_mut().push(x);
185 }
186
187 #[pymethod]
188 pub(crate) fn extend(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
189 let mut new_elements = x.try_to_value(vm)?;
190 self.borrow_vec_mut().append(&mut new_elements);
191 Ok(())
192 }
193
194 #[pymethod]
195 pub(crate) fn insert(&self, position: isize, element: PyObjectRef) {
196 let mut elements = self.borrow_vec_mut();
197 let position = elements.saturate_index(position);
198 elements.insert(position, element);
199 }
200
201 fn concat(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
202 let other = other.downcast_ref::<Self>().ok_or_else(|| {
203 vm.new_type_error(format!(
204 "Cannot add {} and {}",
205 Self::class(&vm.ctx).name(),
206 other.class().name()
207 ))
208 })?;
209 let mut elements = self.borrow_vec().to_vec();
210 elements.extend(other.borrow_vec().iter().cloned());
211 Ok(Self::from(elements).into_ref(&vm.ctx))
212 }
213
214 fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
215 self.concat(&other, vm)
216 }
217
218 fn inplace_concat(
219 zelf: &Py<Self>,
220 other: &PyObject,
221 vm: &VirtualMachine,
222 ) -> PyResult<PyObjectRef> {
223 let mut seq = extract_cloned(other, Ok, vm)?;
224 zelf.borrow_vec_mut().append(&mut seq);
225 Ok(zelf.to_owned().into())
226 }
227
228 fn __iadd__(
229 zelf: PyRef<Self>,
230 other: PyObjectRef,
231 vm: &VirtualMachine,
232 ) -> PyResult<PyRef<Self>> {
233 let mut seq = extract_cloned(&other, Ok, vm)?;
234 zelf.borrow_vec_mut().append(&mut seq);
235 Ok(zelf)
236 }
237
238 #[pymethod]
239 fn clear(&self) {
240 let _removed = core::mem::take(self.borrow_vec_mut().deref_mut());
241 }
242
243 #[pymethod]
244 fn copy(&self, vm: &VirtualMachine) -> PyRef<Self> {
245 Self::from(self.borrow_vec().to_vec()).into_ref(&vm.ctx)
246 }
247
248 #[allow(clippy::len_without_is_empty)]
249 pub fn __len__(&self) -> usize {
250 self.borrow_vec().len()
251 }
252
253 #[pymethod]
254 fn __sizeof__(&self) -> usize {
255 core::mem::size_of::<Self>()
256 + self.elements.read().capacity() * core::mem::size_of::<PyObjectRef>()
257 }
258
259 #[pymethod]
260 fn reverse(&self) {
261 self.borrow_vec_mut().reverse();
262 }
263
264 #[pymethod]
265 fn __reversed__(zelf: PyRef<Self>) -> PyListReverseIterator {
266 let position = zelf.__len__().saturating_sub(1);
267 PyListReverseIterator {
268 internal: PyMutex::new(PositionIterInternal::new(zelf, position)),
269 }
270 }
271
272 fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
273 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
274 SequenceIndex::Int(i) => {
275 let vec = self.borrow_vec();
276 let pos = vec
277 .wrap_index(i)
278 .ok_or_else(|| vm.new_index_error("list index out of range"))?;
279 Ok(vec.do_get(pos))
280 }
281 SequenceIndex::Slice(slice) => self
282 .borrow_vec()
283 .getitem_by_slice(vm, slice)
284 .map(|x| vm.ctx.new_list(x).into()),
285 }
286 }
287
288 fn __getitem__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
289 self._getitem(&needle, vm)
290 }
291
292 fn _setitem(&self, needle: &PyObject, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
293 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
294 SequenceIndex::Int(index) => self
295 .borrow_vec_mut()
296 .setitem_by_index(vm, index, value)
297 .map_err(|e| {
298 if e.class().is(vm.ctx.exceptions.index_error) {
299 vm.new_index_error("list assignment index out of range".to_owned())
300 } else {
301 e
302 }
303 }),
304 SequenceIndex::Slice(slice) => {
305 let sec = extract_cloned(&value, Ok, vm)?;
306 self.borrow_vec_mut().setitem_by_slice(vm, slice, &sec)
307 }
308 }
309 }
310
311 fn __setitem__(
312 &self,
313 needle: PyObjectRef,
314 value: PyObjectRef,
315 vm: &VirtualMachine,
316 ) -> PyResult<()> {
317 self._setitem(&needle, value, vm)
318 }
319
320 fn __mul__(&self, n: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
321 self.repeat(n.into(), vm)
322 }
323
324 fn __imul__(zelf: PyRef<Self>, n: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
325 Self::irepeat(zelf, n.into(), vm)
326 }
327
328 #[pymethod]
329 fn count(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
330 self.mut_count(vm, &needle)
331 }
332
333 pub(crate) fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
334 self.mut_contains(vm, &needle)
335 }
336
337 #[pymethod]
338 fn index(
339 &self,
340 needle: PyObjectRef,
341 range: OptionalRangeArgs,
342 vm: &VirtualMachine,
343 ) -> PyResult<usize> {
344 let (start, stop) = range.saturate(self.__len__(), vm)?;
345 let index = self.mut_index_range(vm, &needle, start..stop)?;
346 if let Some(index) = index.into() {
347 Ok(index)
348 } else {
349 Err(vm.new_value_error(format!("'{}' is not in list", needle.str(vm)?)))
350 }
351 }
352
353 #[pymethod]
354 fn pop(&self, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
355 let mut i = i.into_option().unwrap_or(-1);
356 let mut elements = self.borrow_vec_mut();
357 if i < 0 {
358 i += elements.len() as isize;
359 }
360 if elements.is_empty() {
361 Err(vm.new_index_error("pop from empty list"))
362 } else if i < 0 || i as usize >= elements.len() {
363 Err(vm.new_index_error("pop index out of range"))
364 } else {
365 Ok(elements.remove(i as usize))
366 }
367 }
368
369 #[pymethod]
370 fn remove(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
371 let index = self.mut_index(vm, &needle)?;
372
373 if let Some(index) = index.into() {
374 let is_inside_range = index < self.borrow_vec().len();
376 Ok(is_inside_range.then(|| self.borrow_vec_mut().remove(index)))
377 } else {
378 Err(vm.new_value_error(format!("'{}' is not in list", needle.str(vm)?)))
379 }
380 .map(drop)
381 }
382
383 fn _delitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
384 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
385 SequenceIndex::Int(i) => self.borrow_vec_mut().delitem_by_index(vm, i),
386 SequenceIndex::Slice(slice) => self.borrow_vec_mut().delitem_by_slice(vm, slice),
387 }
388 }
389
390 fn __delitem__(&self, subscript: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
391 self._delitem(&subscript, vm)
392 }
393
394 #[pymethod]
395 pub(crate) fn sort(&self, options: SortOptions, vm: &VirtualMachine) -> PyResult<()> {
396 let (mut elements, version_before) = {
400 let mut guard = self.elements.write();
401 let version_before = self.mutation_counter.load(Ordering::Relaxed);
402 (core::mem::take(guard.deref_mut()), version_before)
403 };
404 let res = do_sort(vm, &mut elements, options.key, options.reverse);
405 let mutated = {
406 let mut guard = self.elements.write();
407 let mutated = self.mutation_counter.load(Ordering::Relaxed) != version_before;
408 core::mem::swap(guard.deref_mut(), &mut elements);
409 mutated
410 };
411 res?;
412
413 if mutated {
414 return Err(vm.new_value_error("list modified during sort"));
415 }
416
417 Ok(())
418 }
419
420 #[pyclassmethod]
421 fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
422 PyGenericAlias::from_args(cls, args, vm)
423 }
424}
425
426fn extract_cloned<F, R>(obj: &PyObject, mut f: F, vm: &VirtualMachine) -> PyResult<Vec<R>>
427where
428 F: FnMut(PyObjectRef) -> PyResult<R>,
429{
430 use crate::builtins::PyTuple;
431 if let Some(tuple) = obj.downcast_ref_if_exact::<PyTuple>(vm) {
432 tuple.iter().map(|x| f(x.clone())).collect()
433 } else if let Some(list) = obj.downcast_ref_if_exact::<PyList>(vm) {
434 list.borrow_vec().iter().map(|x| f(x.clone())).collect()
435 } else {
436 let iter = obj.to_owned().get_iter(vm)?;
437 let iter = iter.iter::<PyObjectRef>(vm)?;
438 let len = obj
439 .sequence_unchecked()
440 .length_opt(vm)
441 .transpose()?
442 .unwrap_or(0);
443 let mut v = Vec::with_capacity(len);
444 for x in iter {
445 v.push(f(x?)?);
446 }
447 v.shrink_to_fit();
448 Ok(v)
449 }
450}
451
452impl MutObjectSequenceOp for PyList {
453 type Inner = [PyObjectRef];
454
455 fn do_get(index: usize, inner: &[PyObjectRef]) -> Option<&PyObject> {
456 inner.get(index).map(|r| r.as_ref())
457 }
458
459 fn do_lock(&self) -> impl core::ops::Deref<Target = [PyObjectRef]> {
460 self.borrow_vec()
461 }
462}
463
464impl Constructor for PyList {
465 type Args = FuncArgs;
466
467 fn py_new(_cls: &Py<PyType>, _args: FuncArgs, _vm: &VirtualMachine) -> PyResult<Self> {
468 Ok(Self::default())
469 }
470}
471
472impl Initializer for PyList {
473 type Args = OptionalArg<PyObjectRef>;
474
475 fn init(zelf: PyRef<Self>, iterable: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
476 let mut elements = if let OptionalArg::Present(iterable) = iterable {
477 iterable.try_to_value(vm)?
478 } else {
479 vec![]
480 };
481 core::mem::swap(zelf.borrow_vec_mut().deref_mut(), &mut elements);
482 Ok(())
483 }
484}
485
486impl AsMapping for PyList {
487 fn as_mapping() -> &'static PyMappingMethods {
488 static AS_MAPPING: PyMappingMethods = PyMappingMethods {
489 length: atomic_func!(|mapping, _vm| Ok(PyList::mapping_downcast(mapping).__len__())),
490 subscript: atomic_func!(
491 |mapping, needle, vm| PyList::mapping_downcast(mapping)._getitem(needle, vm)
492 ),
493 ass_subscript: atomic_func!(|mapping, needle, value, vm| {
494 let zelf = PyList::mapping_downcast(mapping);
495 if let Some(value) = value {
496 zelf._setitem(needle, value, vm)
497 } else {
498 zelf._delitem(needle, vm)
499 }
500 }),
501 };
502 &AS_MAPPING
503 }
504}
505
506impl AsSequence for PyList {
507 fn as_sequence() -> &'static PySequenceMethods {
508 static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
509 length: atomic_func!(|seq, _vm| Ok(PyList::sequence_downcast(seq).__len__())),
510 concat: atomic_func!(|seq, other, vm| {
511 PyList::sequence_downcast(seq)
512 .concat(other, vm)
513 .map(|x| x.into())
514 }),
515 repeat: atomic_func!(|seq, n, vm| {
516 PyList::sequence_downcast(seq)
517 .repeat(n, vm)
518 .map(|x| x.into())
519 }),
520 item: atomic_func!(|seq, i, vm| {
521 let list = PyList::sequence_downcast(seq);
522 let vec = list.borrow_vec();
523 let pos = vec
524 .wrap_index(i)
525 .ok_or_else(|| vm.new_index_error("list index out of range"))?;
526 Ok(vec.do_get(pos))
527 }),
528 ass_item: atomic_func!(|seq, i, value, vm| {
529 let zelf = PyList::sequence_downcast(seq);
530 if let Some(value) = value {
531 zelf.borrow_vec_mut().setitem_by_index(vm, i, value)
532 } else {
533 zelf.borrow_vec_mut().delitem_by_index(vm, i)
534 }
535 .map_err(|e| {
536 if e.class().is(vm.ctx.exceptions.index_error) {
537 vm.new_index_error("list assignment index out of range".to_owned())
538 } else {
539 e
540 }
541 })
542 }),
543 contains: atomic_func!(|seq, target, vm| {
544 let zelf = PyList::sequence_downcast(seq);
545 zelf.mut_contains(vm, target)
546 }),
547 inplace_concat: atomic_func!(|seq, other, vm| {
548 let zelf = PyList::sequence_downcast(seq);
549 PyList::inplace_concat(zelf, other, vm)
550 }),
551 inplace_repeat: atomic_func!(|seq, n, vm| {
552 let zelf = PyList::sequence_downcast(seq);
553 Ok(PyList::irepeat(zelf.to_owned(), n, vm)?.into())
554 }),
555 };
556 &AS_SEQUENCE
557 }
558}
559
560impl Iterable for PyList {
561 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
562 Ok(PyListIterator {
563 internal: PyMutex::new(PositionIterInternal::new(zelf, 0)),
564 }
565 .into_pyobject(vm))
566 }
567}
568
569impl Comparable for PyList {
570 fn cmp(
571 zelf: &Py<Self>,
572 other: &PyObject,
573 op: PyComparisonOp,
574 vm: &VirtualMachine,
575 ) -> PyResult<PyComparisonValue> {
576 if let Some(res) = op.identical_optimization(zelf, other) {
577 return Ok(res.into());
578 }
579 let other = class_or_notimplemented!(Self, other);
580 let a = &*zelf.borrow_vec();
581 let b = &*other.borrow_vec();
582 a.iter()
583 .richcompare(b.iter(), op, vm)
584 .map(PyComparisonValue::Implemented)
585 }
586}
587
588impl Representable for PyList {
589 #[inline]
590 fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
591 if zelf.__len__() == 0 {
592 return Ok(vm.ctx.intern_str("[]").to_owned());
593 }
594
595 if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
596 let mut writer = Wtf8Buf::new();
600 writer.push_char('[');
601
602 let mut elements = zelf.borrow_vec().to_vec();
603 let mut size = zelf.__len__();
604 let mut first = true;
605 let mut i = 0;
606 while i < size {
607 if elements.len() != size {
608 elements = zelf.borrow_vec().to_vec();
610 }
611
612 let item = &elements[i];
613
614 if first {
615 first = false;
616 } else {
617 writer.push_str(", ");
618 }
619
620 writer.push_wtf8(item.repr(vm)?.as_wtf8());
621
622 size = zelf.__len__(); i += 1;
624 }
625
626 writer.push_char(']');
627 Ok(vm.ctx.new_str(writer))
628 } else {
629 Ok(vm.ctx.intern_str("[...]").to_owned())
630 }
631 }
632
633 fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
634 unreachable!("repr() is overridden directly")
635 }
636}
637
638fn do_sort(
639 vm: &VirtualMachine,
640 values: &mut Vec<PyObjectRef>,
641 key_func: Option<PyObjectRef>,
642 reverse: bool,
643) -> PyResult<()> {
644 let cmp = |a: &PyObjectRef, b: &PyObjectRef| {
647 if reverse {
648 a.rich_compare_bool(b, PyComparisonOp::Lt, vm)
650 } else {
651 b.rich_compare_bool(a, PyComparisonOp::Lt, vm)
653 }
654 };
655
656 if let Some(ref key_func) = key_func {
657 let mut items = values
658 .iter()
659 .map(|x| Ok((x.clone(), key_func.call((x.clone(),), vm)?)))
660 .collect::<Result<Vec<_>, _>>()?;
661 timsort::try_sort_by_gt(&mut items, |a, b| cmp(&a.1, &b.1))?;
662 *values = items.into_iter().map(|(val, _)| val).collect();
663 } else {
664 timsort::try_sort_by_gt(values, cmp)?;
665 }
666
667 Ok(())
668}
669
670#[pyclass(module = false, name = "list_iterator", traverse)]
671#[derive(Debug)]
672pub struct PyListIterator {
673 internal: PyMutex<PositionIterInternal<PyListRef>>,
674}
675
676impl PyPayload for PyListIterator {
677 #[inline]
678 fn class(ctx: &Context) -> &'static Py<PyType> {
679 ctx.types.list_iterator_type
680 }
681}
682
683#[pyclass(flags(DISALLOW_INSTANTIATION), with(IterNext, Iterable))]
684impl PyListIterator {
685 #[pymethod]
686 fn __length_hint__(&self) -> usize {
687 self.internal.lock().length_hint(|obj| obj.__len__())
688 }
689
690 #[pymethod]
691 fn __setstate__(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
692 self.internal
693 .lock()
694 .set_state(state, |obj, pos| pos.min(obj.__len__()), vm)
695 }
696
697 #[pymethod]
698 fn __reduce__(&self, vm: &VirtualMachine) -> PyTupleRef {
699 let func = builtins_iter(vm);
700 self.internal.lock().reduce(
701 func,
702 |x| x.clone().into(),
703 |vm| vm.ctx.new_list(Vec::new()).into(),
704 vm,
705 )
706 }
707}
708
709impl PyListIterator {
710 pub(crate) fn fast_next(&self) -> Option<PyObjectRef> {
712 self.internal
713 .lock()
714 .next(|list, pos| {
715 let vec = list.borrow_vec();
716 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
717 })
718 .ok()
719 .and_then(|r| match r {
720 PyIterReturn::Return(v) => Some(v),
721 PyIterReturn::StopIteration(_) => None,
722 })
723 }
724}
725
726impl SelfIter for PyListIterator {}
727impl IterNext for PyListIterator {
728 fn next(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyIterReturn> {
729 zelf.internal.lock().next(|list, pos| {
730 let vec = list.borrow_vec();
731 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
732 })
733 }
734}
735
736#[pyclass(module = false, name = "list_reverseiterator", traverse)]
737#[derive(Debug)]
738pub struct PyListReverseIterator {
739 internal: PyMutex<PositionIterInternal<PyListRef>>,
740}
741
742impl PyPayload for PyListReverseIterator {
743 #[inline]
744 fn class(ctx: &Context) -> &'static Py<PyType> {
745 ctx.types.list_reverseiterator_type
746 }
747}
748
749#[pyclass(flags(DISALLOW_INSTANTIATION), with(IterNext, Iterable))]
750impl PyListReverseIterator {
751 #[pymethod]
752 fn __length_hint__(&self) -> usize {
753 self.internal.lock().rev_length_hint(|obj| obj.__len__())
754 }
755
756 #[pymethod]
757 fn __setstate__(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
758 self.internal
759 .lock()
760 .set_state(state, |obj, pos| pos.min(obj.__len__()), vm)
761 }
762
763 #[pymethod]
764 fn __reduce__(&self, vm: &VirtualMachine) -> PyTupleRef {
765 let func = builtins_reversed(vm);
766 self.internal.lock().reduce(
767 func,
768 |x| x.clone().into(),
769 |vm| vm.ctx.new_list(Vec::new()).into(),
770 vm,
771 )
772 }
773}
774
775impl SelfIter for PyListReverseIterator {}
776impl IterNext for PyListReverseIterator {
777 fn next(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyIterReturn> {
778 zelf.internal.lock().rev_next(|list, pos| {
779 let vec = list.borrow_vec();
780 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
781 })
782 }
783}
784
785fn vectorcall_list(
786 zelf_obj: &PyObject,
787 args: Vec<PyObjectRef>,
788 nargs: usize,
789 kwnames: Option<&[PyObjectRef]>,
790 vm: &VirtualMachine,
791) -> PyResult {
792 let zelf: &Py<PyType> = zelf_obj.downcast_ref().unwrap();
793 let obj = PyList::default().into_ref_with_type(vm, zelf.to_owned())?;
794 let func_args = FuncArgs::from_vectorcall_owned(args, nargs, kwnames);
795 PyList::slot_init(obj.clone().into(), func_args, vm)?;
796 Ok(obj.into())
797}
798
799pub fn init(context: &'static Context) {
800 let list_type = &context.types.list_type;
801 PyList::extend_class(context, list_type);
802 list_type.slots.vectorcall.store(Some(vectorcall_list));
803
804 PyListIterator::extend_class(context, context.types.list_iterator_type);
805 PyListReverseIterator::extend_class(context, context.types.list_reverseiterator_type);
806}