1use super::{PositionIterInternal, PyGenericAlias, PyTupleRef, PyType, PyTypeRef};
2use crate::atomic_func;
3use crate::common::lock::{
4 PyMappedRwLockReadGuard, PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard,
5};
6use crate::{
7 class::PyClassImpl,
8 convert::ToPyObject,
9 function::{ArgSize, FuncArgs, OptionalArg, PyComparisonValue},
10 iter::PyExactSizeIterator,
11 protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
12 recursion::ReprGuard,
13 sequence::{MutObjectSequenceOp, OptionalRangeArgs, SequenceExt, SequenceMutExt},
14 sliceable::{SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp},
15 types::{
16 AsMapping, AsSequence, Comparable, Constructor, Initializer, IterNext, Iterable,
17 PyComparisonOp, Representable, SelfIter, Unconstructible,
18 },
19 utils::collection_repr,
20 vm::VirtualMachine,
21 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
22};
23use std::{fmt, ops::DerefMut};
24
25#[pyclass(module = false, name = "list", unhashable = true, traverse)]
26#[derive(Default)]
27pub struct PyList {
28 elements: PyRwLock<Vec<PyObjectRef>>,
29}
30
31impl fmt::Debug for PyList {
32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 f.write_str("list")
35 }
36}
37
38impl From<Vec<PyObjectRef>> for PyList {
39 fn from(elements: Vec<PyObjectRef>) -> Self {
40 PyList {
41 elements: PyRwLock::new(elements),
42 }
43 }
44}
45
46impl FromIterator<PyObjectRef> for PyList {
47 fn from_iter<T: IntoIterator<Item = PyObjectRef>>(iter: T) -> Self {
48 Vec::from_iter(iter).into()
49 }
50}
51
52impl PyPayload for PyList {
53 fn class(ctx: &Context) -> &'static Py<PyType> {
54 ctx.types.list_type
55 }
56}
57
58impl ToPyObject for Vec<PyObjectRef> {
59 fn to_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
60 PyList::new_ref(self, &vm.ctx).into()
61 }
62}
63
64impl PyList {
65 pub fn new_ref(elements: Vec<PyObjectRef>, ctx: &Context) -> PyRef<Self> {
66 PyRef::new_ref(Self::from(elements), ctx.types.list_type.to_owned(), None)
67 }
68
69 pub fn borrow_vec(&self) -> PyMappedRwLockReadGuard<'_, [PyObjectRef]> {
70 PyRwLockReadGuard::map(self.elements.read(), |v| &**v)
71 }
72
73 pub fn borrow_vec_mut(&self) -> PyRwLockWriteGuard<'_, Vec<PyObjectRef>> {
74 self.elements.write()
75 }
76
77 fn repeat(&self, n: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
78 let elements = &*self.borrow_vec();
79 let v = elements.mul(vm, n)?;
80 Ok(Self::new_ref(v, &vm.ctx))
81 }
82
83 fn irepeat(zelf: PyRef<Self>, n: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
84 zelf.borrow_vec_mut().imul(vm, n)?;
85 Ok(zelf)
86 }
87}
88
89#[derive(FromArgs, Default, Traverse)]
90pub(crate) struct SortOptions {
91 #[pyarg(named, default)]
92 key: Option<PyObjectRef>,
93 #[pytraverse(skip)]
94 #[pyarg(named, default = "false")]
95 reverse: bool,
96}
97
98pub type PyListRef = PyRef<PyList>;
99
100#[pyclass(
101 with(
102 Constructor,
103 Initializer,
104 AsMapping,
105 Iterable,
106 Comparable,
107 AsSequence,
108 Representable
109 ),
110 flags(BASETYPE)
111)]
112impl PyList {
113 #[pymethod]
114 pub(crate) fn append(&self, x: PyObjectRef) {
115 self.borrow_vec_mut().push(x);
116 }
117
118 #[pymethod]
119 pub(crate) fn extend(&self, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
120 let mut new_elements = x.try_to_value(vm)?;
121 self.borrow_vec_mut().append(&mut new_elements);
122 Ok(())
123 }
124
125 #[pymethod]
126 pub(crate) fn insert(&self, position: isize, element: PyObjectRef) {
127 let mut elements = self.borrow_vec_mut();
128 let position = elements.saturate_index(position);
129 elements.insert(position, element);
130 }
131
132 fn concat(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
133 let other = other.payload_if_subclass::<PyList>(vm).ok_or_else(|| {
134 vm.new_type_error(format!(
135 "Cannot add {} and {}",
136 Self::class(&vm.ctx).name(),
137 other.class().name()
138 ))
139 })?;
140 let mut elements = self.borrow_vec().to_vec();
141 elements.extend(other.borrow_vec().iter().cloned());
142 Ok(Self::new_ref(elements, &vm.ctx))
143 }
144
145 #[pymethod(magic)]
146 fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
147 self.concat(&other, vm)
148 }
149
150 fn inplace_concat(
151 zelf: &Py<Self>,
152 other: &PyObject,
153 vm: &VirtualMachine,
154 ) -> PyResult<PyObjectRef> {
155 let mut seq = extract_cloned(other, Ok, vm)?;
156 zelf.borrow_vec_mut().append(&mut seq);
157 Ok(zelf.to_owned().into())
158 }
159
160 #[pymethod(magic)]
161 fn iadd(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
162 let mut seq = extract_cloned(&other, Ok, vm)?;
163 zelf.borrow_vec_mut().append(&mut seq);
164 Ok(zelf)
165 }
166
167 #[pymethod]
168 fn clear(&self) {
169 let _removed = std::mem::take(self.borrow_vec_mut().deref_mut());
170 }
171
172 #[pymethod]
173 fn copy(&self, vm: &VirtualMachine) -> PyRef<Self> {
174 Self::new_ref(self.borrow_vec().to_vec(), &vm.ctx)
175 }
176
177 #[allow(clippy::len_without_is_empty)]
178 #[pymethod(magic)]
179 pub fn len(&self) -> usize {
180 self.borrow_vec().len()
181 }
182
183 #[pymethod(magic)]
184 fn sizeof(&self) -> usize {
185 std::mem::size_of::<Self>()
186 + self.elements.read().capacity() * std::mem::size_of::<PyObjectRef>()
187 }
188
189 #[pymethod]
190 fn reverse(&self) {
191 self.borrow_vec_mut().reverse();
192 }
193
194 #[pymethod(magic)]
195 fn reversed(zelf: PyRef<Self>) -> PyListReverseIterator {
196 let position = zelf.len().saturating_sub(1);
197 PyListReverseIterator {
198 internal: PyMutex::new(PositionIterInternal::new(zelf, position)),
199 }
200 }
201
202 fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
203 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
204 SequenceIndex::Int(i) => self.borrow_vec().getitem_by_index(vm, i),
205 SequenceIndex::Slice(slice) => self
206 .borrow_vec()
207 .getitem_by_slice(vm, slice)
208 .map(|x| vm.ctx.new_list(x).into()),
209 }
210 }
211
212 #[pymethod(magic)]
213 fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
214 self._getitem(&needle, vm)
215 }
216
217 fn _setitem(&self, needle: &PyObject, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
218 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
219 SequenceIndex::Int(index) => self.borrow_vec_mut().setitem_by_index(vm, index, value),
220 SequenceIndex::Slice(slice) => {
221 let sec = extract_cloned(&value, Ok, vm)?;
222 self.borrow_vec_mut().setitem_by_slice(vm, slice, &sec)
223 }
224 }
225 }
226
227 #[pymethod(magic)]
228 fn setitem(
229 &self,
230 needle: PyObjectRef,
231 value: PyObjectRef,
232 vm: &VirtualMachine,
233 ) -> PyResult<()> {
234 self._setitem(&needle, value, vm)
235 }
236
237 #[pymethod(magic)]
238 #[pymethod(name = "__rmul__")]
239 fn mul(&self, n: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
240 self.repeat(n.into(), vm)
241 }
242
243 #[pymethod(magic)]
244 fn imul(zelf: PyRef<Self>, n: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
245 Self::irepeat(zelf, n.into(), vm)
246 }
247
248 #[pymethod]
249 fn count(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
250 self.mut_count(vm, &needle)
251 }
252
253 #[pymethod(magic)]
254 pub(crate) fn contains(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
255 self.mut_contains(vm, &needle)
256 }
257
258 #[pymethod]
259 fn index(
260 &self,
261 needle: PyObjectRef,
262 range: OptionalRangeArgs,
263 vm: &VirtualMachine,
264 ) -> PyResult<usize> {
265 let (start, stop) = range.saturate(self.len(), vm)?;
266 let index = self.mut_index_range(vm, &needle, start..stop)?;
267 if let Some(index) = index.into() {
268 Ok(index)
269 } else {
270 Err(vm.new_value_error(format!("'{}' is not in list", needle.str(vm)?)))
271 }
272 }
273
274 #[pymethod]
275 fn pop(&self, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
276 let mut i = i.into_option().unwrap_or(-1);
277 let mut elements = self.borrow_vec_mut();
278 if i < 0 {
279 i += elements.len() as isize;
280 }
281 if elements.is_empty() {
282 Err(vm.new_index_error("pop from empty list".to_owned()))
283 } else if i < 0 || i as usize >= elements.len() {
284 Err(vm.new_index_error("pop index out of range".to_owned()))
285 } else {
286 Ok(elements.remove(i as usize))
287 }
288 }
289
290 #[pymethod]
291 fn remove(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
292 let index = self.mut_index(vm, &needle)?;
293
294 if let Some(index) = index.into() {
295 let is_inside_range = index < self.borrow_vec().len();
297 Ok(is_inside_range.then(|| self.borrow_vec_mut().remove(index)))
298 } else {
299 Err(vm.new_value_error(format!("'{}' is not in list", needle.str(vm)?)))
300 }
301 .map(drop)
302 }
303
304 fn _delitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
305 match SequenceIndex::try_from_borrowed_object(vm, needle, "list")? {
306 SequenceIndex::Int(i) => self.borrow_vec_mut().delitem_by_index(vm, i),
307 SequenceIndex::Slice(slice) => self.borrow_vec_mut().delitem_by_slice(vm, slice),
308 }
309 }
310
311 #[pymethod(magic)]
312 fn delitem(&self, subscript: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
313 self._delitem(&subscript, vm)
314 }
315
316 #[pymethod]
317 pub(crate) fn sort(&self, options: SortOptions, vm: &VirtualMachine) -> PyResult<()> {
318 let mut elements = std::mem::take(self.borrow_vec_mut().deref_mut());
322 let res = do_sort(vm, &mut elements, options.key, options.reverse);
323 std::mem::swap(self.borrow_vec_mut().deref_mut(), &mut elements);
324 res?;
325
326 if !elements.is_empty() {
327 return Err(vm.new_value_error("list modified during sort".to_owned()));
328 }
329
330 Ok(())
331 }
332
333 #[pyclassmethod(magic)]
334 fn class_getitem(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
335 PyGenericAlias::new(cls, args, vm)
336 }
337}
338
339fn extract_cloned<F, R>(obj: &PyObject, mut f: F, vm: &VirtualMachine) -> PyResult<Vec<R>>
340where
341 F: FnMut(PyObjectRef) -> PyResult<R>,
342{
343 use crate::builtins::PyTuple;
344 if let Some(tuple) = obj.payload_if_exact::<PyTuple>(vm) {
345 tuple.iter().map(|x| f(x.clone())).collect()
346 } else if let Some(list) = obj.payload_if_exact::<PyList>(vm) {
347 list.borrow_vec().iter().map(|x| f(x.clone())).collect()
348 } else {
349 let iter = obj.to_owned().get_iter(vm)?;
350 let iter = iter.iter::<PyObjectRef>(vm)?;
351 let len = obj.to_sequence().length_opt(vm).transpose()?.unwrap_or(0);
352 let mut v = Vec::with_capacity(len);
353 for x in iter {
354 v.push(f(x?)?);
355 }
356 v.shrink_to_fit();
357 Ok(v)
358 }
359}
360
361impl MutObjectSequenceOp for PyList {
362 type Inner = [PyObjectRef];
363
364 fn do_get(index: usize, inner: &[PyObjectRef]) -> Option<&PyObjectRef> {
365 inner.get(index)
366 }
367
368 fn do_lock(&self) -> impl std::ops::Deref<Target = [PyObjectRef]> {
369 self.borrow_vec()
370 }
371}
372
373impl Constructor for PyList {
374 type Args = FuncArgs;
375
376 fn py_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
377 PyList::default()
378 .into_ref_with_type(vm, cls)
379 .map(Into::into)
380 }
381}
382
383impl Initializer for PyList {
384 type Args = OptionalArg<PyObjectRef>;
385
386 fn init(zelf: PyRef<Self>, iterable: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
387 let mut elements = if let OptionalArg::Present(iterable) = iterable {
388 iterable.try_to_value(vm)?
389 } else {
390 vec![]
391 };
392 std::mem::swap(zelf.borrow_vec_mut().deref_mut(), &mut elements);
393 Ok(())
394 }
395}
396
397impl AsMapping for PyList {
398 fn as_mapping() -> &'static PyMappingMethods {
399 static AS_MAPPING: PyMappingMethods = PyMappingMethods {
400 length: atomic_func!(|mapping, _vm| Ok(PyList::mapping_downcast(mapping).len())),
401 subscript: atomic_func!(
402 |mapping, needle, vm| PyList::mapping_downcast(mapping)._getitem(needle, vm)
403 ),
404 ass_subscript: atomic_func!(|mapping, needle, value, vm| {
405 let zelf = PyList::mapping_downcast(mapping);
406 if let Some(value) = value {
407 zelf._setitem(needle, value, vm)
408 } else {
409 zelf._delitem(needle, vm)
410 }
411 }),
412 };
413 &AS_MAPPING
414 }
415}
416
417impl AsSequence for PyList {
418 fn as_sequence() -> &'static PySequenceMethods {
419 static AS_SEQUENCE: PySequenceMethods = PySequenceMethods {
420 length: atomic_func!(|seq, _vm| Ok(PyList::sequence_downcast(seq).len())),
421 concat: atomic_func!(|seq, other, vm| {
422 PyList::sequence_downcast(seq)
423 .concat(other, vm)
424 .map(|x| x.into())
425 }),
426 repeat: atomic_func!(|seq, n, vm| {
427 PyList::sequence_downcast(seq)
428 .repeat(n, vm)
429 .map(|x| x.into())
430 }),
431 item: atomic_func!(|seq, i, vm| {
432 PyList::sequence_downcast(seq)
433 .borrow_vec()
434 .getitem_by_index(vm, i)
435 }),
436 ass_item: atomic_func!(|seq, i, value, vm| {
437 let zelf = PyList::sequence_downcast(seq);
438 if let Some(value) = value {
439 zelf.borrow_vec_mut().setitem_by_index(vm, i, value)
440 } else {
441 zelf.borrow_vec_mut().delitem_by_index(vm, i)
442 }
443 }),
444 contains: atomic_func!(|seq, target, vm| {
445 let zelf = PyList::sequence_downcast(seq);
446 zelf.mut_contains(vm, target)
447 }),
448 inplace_concat: atomic_func!(|seq, other, vm| {
449 let zelf = PyList::sequence_downcast(seq);
450 PyList::inplace_concat(zelf, other, vm)
451 }),
452 inplace_repeat: atomic_func!(|seq, n, vm| {
453 let zelf = PyList::sequence_downcast(seq);
454 Ok(PyList::irepeat(zelf.to_owned(), n, vm)?.into())
455 }),
456 };
457 &AS_SEQUENCE
458 }
459}
460
461impl Iterable for PyList {
462 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
463 Ok(PyListIterator {
464 internal: PyMutex::new(PositionIterInternal::new(zelf, 0)),
465 }
466 .into_pyobject(vm))
467 }
468}
469
470impl Comparable for PyList {
471 fn cmp(
472 zelf: &Py<Self>,
473 other: &PyObject,
474 op: PyComparisonOp,
475 vm: &VirtualMachine,
476 ) -> PyResult<PyComparisonValue> {
477 if let Some(res) = op.identical_optimization(zelf, other) {
478 return Ok(res.into());
479 }
480 let other = class_or_notimplemented!(Self, other);
481 let a = &*zelf.borrow_vec();
482 let b = &*other.borrow_vec();
483 a.iter()
484 .richcompare(b.iter(), op, vm)
485 .map(PyComparisonValue::Implemented)
486 }
487}
488
489impl Representable for PyList {
490 #[inline]
491 fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
492 let s = if zelf.len() == 0 {
493 "[]".to_owned()
494 } else if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
495 collection_repr(None, "[", "]", zelf.borrow_vec().iter(), vm)?
496 } else {
497 "[...]".to_owned()
498 };
499 Ok(s)
500 }
501}
502
503fn do_sort(
504 vm: &VirtualMachine,
505 values: &mut Vec<PyObjectRef>,
506 key_func: Option<PyObjectRef>,
507 reverse: bool,
508) -> PyResult<()> {
509 let op = if reverse {
510 PyComparisonOp::Lt
511 } else {
512 PyComparisonOp::Gt
513 };
514 let cmp = |a: &PyObjectRef, b: &PyObjectRef| a.rich_compare_bool(b, op, vm);
515
516 if let Some(ref key_func) = key_func {
517 let mut items = values
518 .iter()
519 .map(|x| Ok((x.clone(), key_func.call((x.clone(),), vm)?)))
520 .collect::<Result<Vec<_>, _>>()?;
521 timsort::try_sort_by_gt(&mut items, |a, b| cmp(&a.1, &b.1))?;
522 *values = items.into_iter().map(|(val, _)| val).collect();
523 } else {
524 timsort::try_sort_by_gt(values, cmp)?;
525 }
526
527 Ok(())
528}
529
530#[pyclass(module = false, name = "list_iterator", traverse)]
531#[derive(Debug)]
532pub struct PyListIterator {
533 internal: PyMutex<PositionIterInternal<PyListRef>>,
534}
535
536impl PyPayload for PyListIterator {
537 fn class(ctx: &Context) -> &'static Py<PyType> {
538 ctx.types.list_iterator_type
539 }
540}
541
542#[pyclass(with(Unconstructible, IterNext, Iterable))]
543impl PyListIterator {
544 #[pymethod(magic)]
545 fn length_hint(&self) -> usize {
546 self.internal.lock().length_hint(|obj| obj.len())
547 }
548
549 #[pymethod(magic)]
550 fn setstate(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
551 self.internal
552 .lock()
553 .set_state(state, |obj, pos| pos.min(obj.len()), vm)
554 }
555
556 #[pymethod(magic)]
557 fn reduce(&self, vm: &VirtualMachine) -> PyTupleRef {
558 self.internal
559 .lock()
560 .builtins_iter_reduce(|x| x.clone().into(), vm)
561 }
562}
563impl Unconstructible for PyListIterator {}
564
565impl SelfIter for PyListIterator {}
566impl IterNext for PyListIterator {
567 fn next(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyIterReturn> {
568 zelf.internal.lock().next(|list, pos| {
569 let vec = list.borrow_vec();
570 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
571 })
572 }
573}
574
575#[pyclass(module = false, name = "list_reverseiterator", traverse)]
576#[derive(Debug)]
577pub struct PyListReverseIterator {
578 internal: PyMutex<PositionIterInternal<PyListRef>>,
579}
580
581impl PyPayload for PyListReverseIterator {
582 fn class(ctx: &Context) -> &'static Py<PyType> {
583 ctx.types.list_reverseiterator_type
584 }
585}
586
587#[pyclass(with(Unconstructible, IterNext, Iterable))]
588impl PyListReverseIterator {
589 #[pymethod(magic)]
590 fn length_hint(&self) -> usize {
591 self.internal.lock().rev_length_hint(|obj| obj.len())
592 }
593
594 #[pymethod(magic)]
595 fn setstate(&self, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
596 self.internal
597 .lock()
598 .set_state(state, |obj, pos| pos.min(obj.len()), vm)
599 }
600
601 #[pymethod(magic)]
602 fn reduce(&self, vm: &VirtualMachine) -> PyTupleRef {
603 self.internal
604 .lock()
605 .builtins_reversed_reduce(|x| x.clone().into(), vm)
606 }
607}
608impl Unconstructible for PyListReverseIterator {}
609
610impl SelfIter for PyListReverseIterator {}
611impl IterNext for PyListReverseIterator {
612 fn next(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<PyIterReturn> {
613 zelf.internal.lock().rev_next(|list, pos| {
614 let vec = list.borrow_vec();
615 Ok(PyIterReturn::from_result(vec.get(pos).cloned().ok_or(None)))
616 })
617 }
618}
619
620pub fn init(context: &Context) {
621 let list_type = &context.types.list_type;
622 PyList::extend_class(context, list_type);
623
624 PyListIterator::extend_class(context, context.types.list_iterator_type);
625 PyListReverseIterator::extend_class(context, context.types.list_reverseiterator_type);
626}