use crate::{ AsObject, PyObject, PyObjectRef, PyResult, builtins::PyIntRef, function::OptionalArg, sliceable::SequenceIndexOp, types::PyComparisonOp, vm::{MAX_MEMORY_SIZE, VirtualMachine}, }; use optional::Optioned; use std::ops::{Deref, Range}; pub trait MutObjectSequenceOp { type Inner: ?Sized; fn do_get(index: usize, inner: &Self::Inner) -> Option<&PyObjectRef>; fn do_lock(&self) -> impl Deref; fn mut_count(&self, vm: &VirtualMachine, needle: &PyObject) -> PyResult { let mut count = 0; self._mut_iter_equal_skeleton::<_, false>(vm, needle, 0..isize::MAX as usize, || { count += 1 })?; Ok(count) } fn mut_index_range( &self, vm: &VirtualMachine, needle: &PyObject, range: Range, ) -> PyResult> { self._mut_iter_equal_skeleton::<_, true>(vm, needle, range, || {}) } fn mut_index(&self, vm: &VirtualMachine, needle: &PyObject) -> PyResult> { self.mut_index_range(vm, needle, 0..isize::MAX as usize) } fn mut_contains(&self, vm: &VirtualMachine, needle: &PyObject) -> PyResult { self.mut_index(vm, needle).map(|x| x.is_some()) } fn _mut_iter_equal_skeleton( &self, vm: &VirtualMachine, needle: &PyObject, range: Range, mut f: F, ) -> PyResult> where F: FnMut(), { let mut borrower = None; let mut i = range.start; let index = loop { if i >= range.end { break Optioned::::none(); } let guard = if let Some(x) = borrower.take() { x } else { self.do_lock() }; let elem = if let Some(x) = Self::do_get(i, &guard) { x } else { break Optioned::::none(); }; if elem.is(needle) { f(); if SHORT { break Optioned::::some(i); } borrower = Some(guard); } else { let elem = elem.clone(); drop(guard); if elem.rich_compare_bool(needle, PyComparisonOp::Eq, vm)? { f(); if SHORT { break Optioned::::some(i); } } } i += 1; }; Ok(index) } } pub trait SequenceExt where Self: AsRef<[T]>, { fn mul(&self, vm: &VirtualMachine, n: isize) -> PyResult> { let n = vm.check_repeat_or_overflow_error(self.as_ref().len(), n)?; if n > 1 && std::mem::size_of_val(self.as_ref()) >= MAX_MEMORY_SIZE / n { return Err(vm.new_memory_error("".to_owned())); } let mut v = Vec::with_capacity(n * self.as_ref().len()); for _ in 0..n { v.extend_from_slice(self.as_ref()); } Ok(v) } } impl SequenceExt for [T] {} pub trait SequenceMutExt where Self: AsRef<[T]>, { fn as_vec_mut(&mut self) -> &mut Vec; fn imul(&mut self, vm: &VirtualMachine, n: isize) -> PyResult<()> { let n = vm.check_repeat_or_overflow_error(self.as_ref().len(), n)?; if n == 0 { self.as_vec_mut().clear(); } else if n != 1 { let mut sample = self.as_vec_mut().clone(); if n != 2 { self.as_vec_mut().reserve(sample.len() * (n - 1)); for _ in 0..n - 2 { self.as_vec_mut().extend_from_slice(&sample); } } self.as_vec_mut().append(&mut sample); } Ok(()) } } impl SequenceMutExt for Vec { fn as_vec_mut(&mut self) -> &mut Vec { self } } #[derive(FromArgs)] pub struct OptionalRangeArgs { #[pyarg(positional, optional)] start: OptionalArg, #[pyarg(positional, optional)] stop: OptionalArg, } impl OptionalRangeArgs { pub fn saturate(self, len: usize, vm: &VirtualMachine) -> PyResult<(usize, usize)> { let saturate = |obj: PyObjectRef| -> PyResult<_> { obj.try_into_value(vm) .map(|int: PyIntRef| int.as_bigint().saturated_at(len)) }; let start = self.start.map_or(Ok(0), saturate)?; let stop = self.stop.map_or(Ok(len), saturate)?; Ok((start, stop)) } }