diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index ad01049b5e..a835d7a763 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -48,31 +48,6 @@ pub struct PyByteArray { pub type PyByteArrayRef = PyRef; -impl PyByteArray { - pub fn new_ref(data: Vec, ctx: &Context) -> PyRef { - PyRef::new_ref(Self::from(data), ctx.types.bytearray_type.to_owned(), None) - } - - fn from_inner(inner: PyBytesInner) -> Self { - PyByteArray { - inner: PyRwLock::new(inner), - exports: AtomicUsize::new(0), - } - } - - pub fn borrow_buf(&self) -> PyMappedRwLockReadGuard<'_, [u8]> { - PyRwLockReadGuard::map(self.inner.read(), |inner| &*inner.elements) - } - - pub fn borrow_buf_mut(&self) -> PyMappedRwLockWriteGuard<'_, Vec> { - PyRwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.elements) - } - - fn repeat(&self, value: isize, vm: &VirtualMachine) -> PyResult { - self.inner().mul(value, vm).map(|x| x.into()) - } -} - impl From for PyByteArray { fn from(inner: PyBytesInner) -> Self { Self::from_inner(inner) @@ -97,9 +72,107 @@ pub(crate) fn init(context: &Context) { PyByteArrayIterator::extend_class(context, context.types.bytearray_iterator_type); } +impl PyByteArray { + pub fn new_ref(data: Vec, ctx: &Context) -> PyRef { + PyRef::new_ref(Self::from(data), ctx.types.bytearray_type.to_owned(), None) + } + + fn from_inner(inner: PyBytesInner) -> Self { + PyByteArray { + inner: PyRwLock::new(inner), + exports: AtomicUsize::new(0), + } + } + + pub fn borrow_buf(&self) -> PyMappedRwLockReadGuard<'_, [u8]> { + PyRwLockReadGuard::map(self.inner.read(), |inner| &*inner.elements) + } + + pub fn borrow_buf_mut(&self) -> PyMappedRwLockWriteGuard<'_, Vec> { + PyRwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.elements) + } + + fn repeat(&self, value: isize, vm: &VirtualMachine) -> PyResult { + self.inner().mul(value, vm).map(|x| x.into()) + } + + fn _setitem_by_index(&self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + let value = value_from_object(vm, &value)?; + self.borrow_buf_mut().setitem_by_index(vm, i, value) + } + + fn _setitem( + zelf: &Py, + needle: &PyObject, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? { + SequenceIndex::Int(i) => zelf._setitem_by_index(i, value, vm), + SequenceIndex::Slice(slice) => { + let items = if zelf.is(&value) { + zelf.borrow_buf().to_vec() + } else { + bytes_from_object(vm, &value)? + }; + if let Some(mut w) = zelf.try_resizable_opt() { + w.elements.setitem_by_slice(vm, slice, &items) + } else { + zelf.borrow_buf_mut() + .setitem_by_slice_no_resize(vm, slice, &items) + } + } + } + } + + fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult { + match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? { + SequenceIndex::Int(i) => self + .borrow_buf() + .getitem_by_index(vm, i) + .map(|x| vm.ctx.new_int(x).into()), + SequenceIndex::Slice(slice) => self + .borrow_buf() + .getitem_by_slice(vm, slice) + .map(|x| Self::new_ref(x, &vm.ctx).into()), + } + } + + pub fn _delitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<()> { + match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? { + SequenceIndex::Int(i) => self.try_resizable(vm)?.elements.delitem_by_index(vm, i), + SequenceIndex::Slice(slice) => { + // TODO: delete 0 elements don't need resizable + self.try_resizable(vm)?.elements.delitem_by_slice(vm, slice) + } + } + } + + fn irepeat(zelf: &Py, n: isize, vm: &VirtualMachine) -> PyResult<()> { + if n == 1 { + return Ok(()); + } + let mut w = match zelf.try_resizable(vm) { + Ok(w) => w, + Err(err) => { + return if zelf.borrow_buf().is_empty() { + // We can multiple an empty vector by any integer + Ok(()) + } else { + Err(err) + }; + } + }; + + w.imul(n, vm) + } +} + #[pyclass( flags(BASETYPE), with( + Py, + PyRef, Constructor, Initializer, Comparable, @@ -156,45 +229,6 @@ impl PyByteArray { self.inner().contains(needle, vm) } - fn _setitem_by_index(&self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - let value = value_from_object(vm, &value)?; - self.borrow_buf_mut().setitem_by_index(vm, i, value) - } - - fn _setitem( - zelf: PyRef, - needle: &PyObject, - value: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult<()> { - match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? { - SequenceIndex::Int(i) => zelf._setitem_by_index(i, value, vm), - SequenceIndex::Slice(slice) => { - let items = if zelf.is(&value) { - zelf.borrow_buf().to_vec() - } else { - bytes_from_object(vm, &value)? - }; - if let Some(mut w) = zelf.try_resizable_opt() { - w.elements.setitem_by_slice(vm, slice, &items) - } else { - zelf.borrow_buf_mut() - .setitem_by_slice_no_resize(vm, slice, &items) - } - } - } - } - - #[pymethod(magic)] - fn setitem( - zelf: PyRef, - needle: PyObjectRef, - value: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult<()> { - Self::_setitem(zelf, &needle, value, vm) - } - #[pymethod(magic)] fn iadd(zelf: PyRef, other: ArgBytesLike, vm: &VirtualMachine) -> PyResult> { zelf.try_resizable(vm)? @@ -203,34 +237,11 @@ impl PyByteArray { Ok(zelf) } - fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult { - match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? { - SequenceIndex::Int(i) => self - .borrow_buf() - .getitem_by_index(vm, i) - .map(|x| vm.ctx.new_int(x).into()), - SequenceIndex::Slice(slice) => self - .borrow_buf() - .getitem_by_slice(vm, slice) - .map(|x| Self::new_ref(x, &vm.ctx).into()), - } - } - #[pymethod(magic)] fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { self._getitem(&needle, vm) } - pub fn _delitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<()> { - match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? { - SequenceIndex::Int(i) => self.try_resizable(vm)?.elements.delitem_by_index(vm, i), - SequenceIndex::Slice(slice) => { - // TODO: delete 0 elements don't need resizable - self.try_resizable(vm)?.elements.delitem_by_slice(vm, slice) - } - } - } - #[pymethod(magic)] pub fn delitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { self._delitem(&needle, vm) @@ -241,78 +252,6 @@ impl PyByteArray { PyBytesInner::maketrans(from, to, vm) } - #[pymethod] - fn pop(zelf: PyRef, index: OptionalArg, vm: &VirtualMachine) -> PyResult { - let elements = &mut zelf.try_resizable(vm)?.elements; - let index = elements - .wrap_index(index.unwrap_or(-1)) - .ok_or_else(|| vm.new_index_error("index out of range".to_owned()))?; - Ok(elements.remove(index)) - } - - #[pymethod] - fn insert( - zelf: PyRef, - index: isize, - object: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult<()> { - let value = value_from_object(vm, &object)?; - let elements = &mut zelf.try_resizable(vm)?.elements; - let index = elements.saturate_index(index); - elements.insert(index, value); - Ok(()) - } - - #[pymethod] - fn append(zelf: PyRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - let value = value_from_object(vm, &object)?; - zelf.try_resizable(vm)?.elements.push(value); - Ok(()) - } - - #[pymethod] - fn remove(zelf: PyRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - let value = value_from_object(vm, &object)?; - let elements = &mut zelf.try_resizable(vm)?.elements; - if let Some(index) = elements.find_byte(value) { - elements.remove(index); - Ok(()) - } else { - Err(vm.new_value_error("value not found in bytearray".to_owned())) - } - } - - #[pymethod] - fn extend(zelf: PyRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - if zelf.is(&object) { - Self::irepeat(&zelf, 2, vm) - } else { - let items = bytes_from_object(vm, &object)?; - zelf.try_resizable(vm)?.elements.extend(items); - Ok(()) - } - } - - fn irepeat(zelf: &Py, n: isize, vm: &VirtualMachine) -> PyResult<()> { - if n == 1 { - return Ok(()); - } - let mut w = match zelf.try_resizable(vm) { - Ok(w) => w, - Err(err) => { - return if zelf.borrow_buf().is_empty() { - // We can multiple an empty vector by any integer - Ok(()) - } else { - Err(err) - }; - } - }; - - w.imul(n, vm) - } - #[pymethod] fn isalnum(&self) -> bool { self.inner().isalnum() @@ -503,59 +442,11 @@ impl PyByteArray { self.inner().strip(chars).into() } - #[pymethod] - fn lstrip( - zelf: PyRef, - chars: OptionalOption, - vm: &VirtualMachine, - ) -> PyRef { - let inner = zelf.inner(); - let stripped = inner.lstrip(chars); - let elements = &inner.elements; - if stripped == elements { - drop(inner); - zelf - } else { - vm.new_pyref(PyByteArray::from(stripped.to_vec())) - } - } - - #[pymethod] - fn rstrip( - zelf: PyRef, - chars: OptionalOption, - vm: &VirtualMachine, - ) -> PyRef { - let inner = zelf.inner(); - let stripped = inner.rstrip(chars); - let elements = &inner.elements; - if stripped == elements { - drop(inner); - zelf - } else { - vm.new_pyref(PyByteArray::from(stripped.to_vec())) - } - } - - /// removeprefix($self, prefix, /) - /// - /// - /// Return a bytearray object with the given prefix string removed if present. - /// - /// If the bytearray starts with the prefix string, return string[len(prefix):] - /// Otherwise, return a copy of the original bytearray. #[pymethod] fn removeprefix(&self, prefix: PyBytesInner) -> Self { self.inner().removeprefix(prefix).into() } - /// removesuffix(self, prefix, /) - /// - /// - /// Return a bytearray object with the given suffix string removed if present. - /// - /// If the bytearray ends with the suffix string, return string[:len(suffix)] - /// Otherwise, return a copy of the original bytearray. #[pymethod] fn removesuffix(&self, suffix: PyBytesInner) -> Self { self.inner().removesuffix(suffix).to_vec().into() @@ -638,12 +529,6 @@ impl PyByteArray { Ok(self.inner().replace(old, new, count, vm)?.into()) } - #[pymethod] - fn clear(zelf: PyRef, vm: &VirtualMachine) -> PyResult<()> { - zelf.try_resizable(vm)?.elements.clear(); - Ok(()) - } - #[pymethod] fn copy(&self) -> Self { self.borrow_buf().to_vec().into() @@ -681,35 +566,135 @@ impl PyByteArray { fn reverse(&self) { self.borrow_buf_mut().reverse(); } +} + +#[pyclass] +impl Py { + #[pymethod(magic)] + fn setitem( + &self, + needle: PyObjectRef, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + PyByteArray::_setitem(self, &needle, value, vm) + } #[pymethod] - fn decode(zelf: PyRef, args: DecodeArgs, vm: &VirtualMachine) -> PyResult { - bytes_decode(zelf.into(), args, vm) + fn pop(&self, index: OptionalArg, vm: &VirtualMachine) -> PyResult { + let elements = &mut self.try_resizable(vm)?.elements; + let index = elements + .wrap_index(index.unwrap_or(-1)) + .ok_or_else(|| vm.new_index_error("index out of range".to_owned()))?; + Ok(elements.remove(index)) + } + + #[pymethod] + fn insert(&self, index: isize, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + let value = value_from_object(vm, &object)?; + let elements = &mut self.try_resizable(vm)?.elements; + let index = elements.saturate_index(index); + elements.insert(index, value); + Ok(()) + } + + #[pymethod] + fn append(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + let value = value_from_object(vm, &object)?; + self.try_resizable(vm)?.elements.push(value); + Ok(()) + } + + #[pymethod] + fn remove(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + let value = value_from_object(vm, &object)?; + let elements = &mut self.try_resizable(vm)?.elements; + let index = elements + .find_byte(value) + .ok_or_else(|| vm.new_value_error("value not found in bytearray".to_owned()))?; + elements.remove(index); + Ok(()) + } + + #[pymethod] + fn extend(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + if self.is(&object) { + PyByteArray::irepeat(self, 2, vm) + } else { + let items = bytes_from_object(vm, &object)?; + self.try_resizable(vm)?.elements.extend(items); + Ok(()) + } + } + + #[pymethod] + fn clear(&self, vm: &VirtualMachine) -> PyResult<()> { + self.try_resizable(vm)?.elements.clear(); + Ok(()) } #[pymethod(magic)] fn reduce_ex( - zelf: PyRef, + &self, _proto: usize, vm: &VirtualMachine, ) -> (PyTypeRef, PyTupleRef, Option) { - Self::reduce(zelf, vm) + Self::reduce(self, vm) } #[pymethod(magic)] - fn reduce( - zelf: PyRef, - vm: &VirtualMachine, - ) -> (PyTypeRef, PyTupleRef, Option) { - let bytes = PyBytes::from(zelf.borrow_buf().to_vec()).to_pyobject(vm); + fn reduce(&self, vm: &VirtualMachine) -> (PyTypeRef, PyTupleRef, Option) { + let bytes = PyBytes::from(self.borrow_buf().to_vec()).to_pyobject(vm); ( - zelf.class().to_owned(), + self.class().to_owned(), PyTuple::new_ref(vec![bytes], &vm.ctx), - zelf.as_object().dict(), + self.as_object().dict(), ) } } +#[pyclass] +impl PyRef { + #[pymethod] + fn lstrip( + self, + chars: OptionalOption, + vm: &VirtualMachine, + ) -> PyRef { + let inner = self.inner(); + let stripped = inner.lstrip(chars); + let elements = &inner.elements; + if stripped == elements { + drop(inner); + self + } else { + vm.new_pyref(PyByteArray::from(stripped.to_vec())) + } + } + + #[pymethod] + fn rstrip( + self, + chars: OptionalOption, + vm: &VirtualMachine, + ) -> PyRef { + let inner = self.inner(); + let stripped = inner.rstrip(chars); + let elements = &inner.elements; + if stripped == elements { + drop(inner); + self + } else { + vm.new_pyref(PyByteArray::from(stripped.to_vec())) + } + } + + #[pymethod] + fn decode(self, args: DecodeArgs, vm: &VirtualMachine) -> PyResult { + bytes_decode(self.into(), args, vm) + } +} + impl Constructor for PyByteArray { type Args = FuncArgs; @@ -796,7 +781,7 @@ impl AsMapping for PyByteArray { ass_subscript: atomic_func!(|mapping, needle, value, vm| { let zelf = PyByteArray::mapping_downcast(mapping); if let Some(value) = value { - PyByteArray::setitem(zelf.to_owned(), needle.to_owned(), value, vm) + Py::setitem(zelf, needle.to_owned(), value, vm) } else { zelf.delitem(needle.to_owned(), vm) }