diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 29a675e11..4cd11b920 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -12,16 +12,16 @@ mod array { }; use crate::vm::{ builtins::{ - IntoPyFloat, PyByteArray, PyBytes, PyBytesRef, PyIntRef, PyList, PyListRef, PySliceRef, - PyStr, PyStrRef, PyTypeRef, + dict::PyMapping, IntoPyFloat, PyByteArray, PyBytes, PyBytesRef, PyIntRef, PyList, + PyListRef, PySliceRef, PyStr, PyStrRef, PyTypeRef, }, class_or_notimplemented, function::{ArgBytesLike, ArgIterable, OptionalArg}, protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard}, sliceable::{saturate_index, PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ - AsBuffer, Comparable, Iterable, IteratorIterable, PyComparisonOp, SlotConstructor, - SlotIterator, + AsBuffer, AsMapping, Comparable, Iterable, IteratorIterable, PyComparisonOp, + SlotConstructor, SlotIterator, }, IdProtocol, IntoPyObject, IntoPyResult, PyComparisonValue, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, VirtualMachine, @@ -665,7 +665,10 @@ mod array { } } - #[pyimpl(flags(BASETYPE), with(Comparable, AsBuffer, Iterable, SlotConstructor))] + #[pyimpl( + flags(BASETYPE), + with(Comparable, AsBuffer, AsMapping, Iterable, SlotConstructor) + )] impl PyArray { fn read(&self) -> PyRwLockReadGuard<'_, ArrayContentType> { self.array.read() @@ -1161,6 +1164,33 @@ mod array { } } + impl AsMapping for PyArray { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: Some(Self::ass_subscript), + }) + } + + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))? + } + + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))? + } + + fn ass_subscript( + zelf: PyObjectRef, + needle: PyObjectRef, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))? + } + } + impl Iterable for PyArray { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { Ok(PyArrayIter { diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 2ab6091dc..4dd908a72 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -9,6 +9,7 @@ use crate::common::{ }; use crate::{ anystr::{self, AnyStr}, + builtins::dict::PyMapping, bytesinner::{ bytes_decode, bytes_from_object, value_from_object, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, @@ -18,8 +19,8 @@ use crate::{ protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard}, sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ - AsBuffer, Callable, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, - SlotIterator, Unhashable, + AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable, + PyComparisonOp, SlotIterator, Unhashable, }, utils::Either, IdProtocol, IntoPyObject, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, @@ -95,7 +96,10 @@ pub(crate) fn init(context: &PyContext) { PyByteArrayIterator::extend_class(context, &context.types.bytearray_iterator_type); } -#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, AsBuffer, Iterable))] +#[pyimpl( + flags(BASETYPE), + with(Hashable, Comparable, AsBuffer, AsMapping, Iterable) +)] impl PyByteArray { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { @@ -712,6 +716,36 @@ impl<'a> ResizeGuard<'a> for PyByteArray { } } +impl AsMapping for PyByteArray { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: Some(Self::ass_subscript), + }) + } + + #[inline] + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))? + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + needle: PyObjectRef, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))? + } +} + impl Unhashable for PyByteArray {} impl Iterable for PyByteArray { diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 2df600017..5cfe28588 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -1,6 +1,7 @@ use super::{PyDictRef, PyIntRef, PyStrRef, PyTupleRef, PyTypeRef}; use crate::{ anystr::{self, AnyStr}, + builtins::dict::PyMapping, bytesinner::{ bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner, @@ -9,8 +10,8 @@ use crate::{ function::{ArgBytesLike, ArgIterable, OptionalArg, OptionalOption}, protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn}, slots::{ - AsBuffer, Callable, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, - SlotConstructor, SlotIterator, + AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable, + PyComparisonOp, SlotConstructor, SlotIterator, }, utils::Either, IdProtocol, IntoPyObject, IntoPyResult, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, @@ -103,7 +104,7 @@ impl SlotConstructor for PyBytes { #[pyimpl( flags(BASETYPE), - with(Hashable, Comparable, AsBuffer, Iterable, SlotConstructor) + with(AsMapping, Hashable, Comparable, AsBuffer, Iterable, SlotConstructor) )] impl PyBytes { #[pymethod(magic)] @@ -540,6 +541,36 @@ impl BufferInternal for PyRef { fn retain(&self) {} } +impl AsMapping for PyBytes { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: None, + }) + } + + #[inline] + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))? + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + _needle: PyObjectRef, + _value: PyObjectRef, + _vm: &VirtualMachine, + ) -> PyResult<()> { + unreachable!("ass_subscript not implemented for {}", zelf.class()) + } +} + impl Hashable for PyBytes { fn hash(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { Ok(zelf.inner.hash(vm)) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index a65dc47a7..efb4f2cc4 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -6,7 +6,8 @@ use crate::{ function::{ArgIterable, FuncArgs, KwArgs, OptionalArg}, protocol::PyIterReturn, slots::{ - Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, Unhashable, + AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, + Unhashable, }, vm::{ReprGuard, VirtualMachine}, IdProtocol, IntoPyObject, ItemProtocol, @@ -51,7 +52,7 @@ impl PyValue for PyDict { // Python dict methods: #[allow(clippy::len_without_is_empty)] -#[pyimpl(with(Hashable, Comparable, Iterable), flags(BASETYPE))] +#[pyimpl(with(AsMapping, Hashable, Comparable, Iterable), flags(BASETYPE))] impl PyDict { #[pyslot] fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { @@ -410,6 +411,36 @@ impl PyDict { } } +impl AsMapping for PyDict { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: Some(Self::ass_subscript), + }) + } + + #[inline] + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))? + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast(zelf, vm).map(|zelf| Self::getitem(zelf, needle, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + needle: PyObjectRef, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.setitem(needle, value, vm))? + } +} + impl Comparable for PyDict { fn cmp( zelf: &PyRef, diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index 1f0fdfad5..deeaecf0a 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -7,12 +7,14 @@ use crate::common::lock::{ PyMappedRwLockReadGuard, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard, }; use crate::{ + builtins::dict::PyMapping, function::{ArgIterable, FuncArgs, OptionalArg}, protocol::PyIterReturn, sequence::{self, SimpleSeq}, sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ - Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, Unhashable, + AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, + Unhashable, }, utils::Either, vm::{ReprGuard, VirtualMachine}, @@ -82,7 +84,7 @@ pub(crate) struct SortOptions { pub type PyListRef = PyRef; -#[pyimpl(with(Iterable, Hashable, Comparable), flags(BASETYPE))] +#[pyimpl(with(AsMapping, Iterable, Hashable, Comparable), flags(BASETYPE))] impl PyList { #[pymethod] pub(crate) fn append(&self, x: PyObjectRef) { @@ -416,6 +418,36 @@ impl PyList { } } +impl AsMapping for PyList { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: Some(Self::ass_subscript), + }) + } + + #[inline] + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))? + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast(zelf, vm).map(|zelf| Self::getitem(zelf, needle, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + needle: PyObjectRef, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.setitem(needle, value, vm))? + } +} + impl Iterable for PyList { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { Ok(PyListIterator { diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index fcf7d9071..b8e080cf6 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -1,9 +1,10 @@ use super::{PyDict, PyStrRef, PyTypeRef}; use crate::{ + builtins::dict::PyMapping, function::OptionalArg, - slots::{Iterable, SlotConstructor}, + slots::{AsMapping, Iterable, SlotConstructor}, IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, - TryFromObject, VirtualMachine, + TryFromObject, TypeProtocol, VirtualMachine, }; #[pyclass(module = false, name = "mappingproxy")] @@ -43,7 +44,7 @@ impl SlotConstructor for PyMappingProxy { } } -#[pyimpl(with(Iterable, SlotConstructor))] +#[pyimpl(with(AsMapping, Iterable, SlotConstructor))] impl PyMappingProxy { fn get_inner(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult> { let opt = match &self.mapping { @@ -127,6 +128,37 @@ impl PyMappingProxy { } } } + +impl AsMapping for PyMappingProxy { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: None, + subscript: Some(Self::subscript), + ass_subscript: None, + }) + } + + #[inline] + fn length(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult { + unreachable!("length not implemented for {}", zelf.class()) + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + _needle: PyObjectRef, + _value: PyObjectRef, + _vm: &VirtualMachine, + ) -> PyResult<()> { + unreachable!("ass_subscript not implemented for {}", zelf.class()) + } +} + impl Iterable for PyMappingProxy { fn iter(zelf: PyRef, vm: &VirtualMachine) -> PyResult { let obj = match &zelf.mapping { diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index eaf8539c7..e2180f778 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -6,11 +6,12 @@ use crate::common::{ rc::PyRc, }; use crate::{ + builtins::dict::PyMapping, bytesinner::bytes_to_hex, function::{FuncArgs, OptionalArg}, protocol::{BufferInternal, BufferOptions, PyBuffer}, sliceable::{convert_slice, wrap_index, SequenceIndex}, - slots::{AsBuffer, Comparable, Hashable, PyComparisonOp, SlotConstructor}, + slots::{AsBuffer, AsMapping, Comparable, Hashable, PyComparisonOp, SlotConstructor}, stdlib::pystruct::FormatSpec, utils::Either, IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, @@ -53,7 +54,7 @@ impl SlotConstructor for PyMemoryView { } } -#[pyimpl(with(Hashable, Comparable, AsBuffer, SlotConstructor))] +#[pyimpl(with(Hashable, Comparable, AsBuffer, AsMapping, SlotConstructor))] impl PyMemoryView { #[cfg(debug_assertions)] fn validate(self) -> Self { @@ -734,6 +735,39 @@ impl BufferInternal for PyRef { fn retain(&self) {} } +impl AsMapping for PyMemoryView { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: Some(Self::ass_subscript), + }) + } + + #[inline] + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.len(vm))? + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast(zelf, vm) + .map(|zelf| Self::getitem(zelf, SequenceIndex::try_from_object(vm, needle)?, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + needle: PyObjectRef, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + Self::downcast(zelf, vm).map(|zelf| { + Self::setitem(zelf, SequenceIndex::try_from_object(vm, needle)?, value, vm) + })? + } +} + impl Comparable for PyMemoryView { fn cmp( zelf: &PyRef, diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index d9e88b667..2b2401084 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -1,9 +1,12 @@ use super::{PyInt, PyIntRef, PySlice, PySliceRef, PyTypeRef}; use crate::common::hash::PyHash; use crate::{ + builtins::dict::PyMapping, function::{FuncArgs, OptionalArg}, protocol::PyIterReturn, - slots::{Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator}, + slots::{ + AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, + }, IdProtocol, IntoPyRef, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, VirtualMachine, }; @@ -173,7 +176,7 @@ pub fn init(context: &PyContext) { PyRangeIterator::extend_class(context, &context.types.range_iterator_type); } -#[pyimpl(with(Hashable, Comparable, Iterable))] +#[pyimpl(with(AsMapping, Hashable, Comparable, Iterable))] impl PyRange { fn new(cls: PyTypeRef, stop: PyIntRef, vm: &VirtualMachine) -> PyResult> { PyRange { @@ -372,6 +375,37 @@ impl PyRange { } } +impl AsMapping for PyRange { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: None, + }) + } + + #[inline] + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len().to_usize().unwrap()))? + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm) + .map(|zelf| zelf.getitem(RangeIndex::try_from_object(vm, needle)?, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + _needle: PyObjectRef, + _value: PyObjectRef, + _vm: &VirtualMachine, + ) -> PyResult<()> { + unreachable!("ass_subscript not implemented for {}", zelf.class()) + } +} + impl Hashable for PyRange { fn hash(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { let length = zelf.compute_length(); diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 03c11d4e5..bb662140c 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -3,6 +3,7 @@ use super::{ iter::IterStatus::{self, Active, Exhausted}, PyInt, PyTypeRef, }; +use crate::builtins::dict::PyMapping; use crate::common::hash::PyHash; use crate::{ function::OptionalArg, @@ -10,8 +11,8 @@ use crate::{ sequence::{self, SimpleSeq}, sliceable::PySliceableSequence, slots::{ - Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotConstructor, - SlotIterator, + AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, + SlotConstructor, SlotIterator, }, utils::Either, vm::{ReprGuard, VirtualMachine}, @@ -111,7 +112,10 @@ impl SlotConstructor for PyTuple { } } -#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, Iterable, SlotConstructor))] +#[pyimpl( + flags(BASETYPE), + with(AsMapping, Hashable, Comparable, Iterable, SlotConstructor) +)] impl PyTuple { /// Creating a new tuple with given boxed slice. /// NOTE: for usual case, you probably want to use PyTupleRef::with_elements. @@ -284,6 +288,36 @@ impl PyTuple { } } +impl AsMapping for PyTuple { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMapping { + length: Some(Self::length), + subscript: Some(Self::subscript), + ass_subscript: None, + }) + } + + #[inline] + fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))? + } + + #[inline] + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Self::downcast(zelf, vm).map(|zelf| Self::getitem(zelf, needle, vm))? + } + + #[inline] + fn ass_subscript( + zelf: PyObjectRef, + _needle: PyObjectRef, + _value: PyObjectRef, + _vm: &VirtualMachine, + ) -> PyResult<()> { + unreachable!("ass_subscript not implemented for {}", zelf.class()) + } +} + impl Hashable for PyTuple { fn hash(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { crate::utils::hash_iter(zelf.elements.iter(), vm)