Skip to content

Implement Mapping Protocol #3121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 2, 2021
Merged
45 changes: 41 additions & 4 deletions stdlib/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ mod array {
},
class_or_notimplemented,
function::{ArgBytesLike, ArgIterable, OptionalArg},
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard},
protocol::{
BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods, 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,
Expand Down Expand Up @@ -665,7 +667,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()
Expand Down Expand Up @@ -1161,6 +1166,38 @@ mod array {
}
}

impl AsMapping for PyArray {
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
Ok(PyMappingMethods {
length: Some(Self::length),
subscript: Some(Self::subscript),
ass_subscript: Some(Self::ass_subscript),
})
}

fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
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: Option<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
match value {
Some(value) => {
Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))?
}
None => Self::downcast(zelf, vm).map(|zelf| Self::delitem(zelf, needle, vm))?,
}
}
}

impl Iterable for PyArray {
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
Ok(PyArrayIter {
Expand Down
52 changes: 46 additions & 6 deletions vm/src/builtins/bytearray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ use crate::{
ByteInnerTranslateOptions, DecodeArgs, PyBytesInner,
},
function::{ArgBytesLike, ArgIterable, FuncArgs, OptionalArg, OptionalOption},
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard},
protocol::{
BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods, 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,
Expand Down Expand Up @@ -95,7 +97,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 {
Expand Down Expand Up @@ -201,9 +206,9 @@ impl PyByteArray {
}

#[pymethod(magic)]
pub fn delitem(&self, needle: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
pub fn delitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let elements = &mut self.try_resizable(vm)?.elements;
match needle {
match SequenceIndex::try_from_object_for(vm, needle, Self::NAME)? {
SequenceIndex::Int(int) => {
if let Some(idx) = elements.wrap_index(int) {
elements.remove(idx);
Expand Down Expand Up @@ -712,6 +717,41 @@ impl<'a> ResizeGuard<'a> for PyByteArray {
}
}

impl AsMapping for PyByteArray {
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
Ok(PyMappingMethods {
length: Some(Self::length),
subscript: Some(Self::subscript),
ass_subscript: Some(Self::ass_subscript),
})
}

#[inline]
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
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: Option<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
match value {
Some(value) => {
Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))
}
None => Self::downcast_ref(&zelf, vm).map(|zelf| zelf.delitem(needle, vm)),
}?
}
}

impl Unhashable for PyByteArray {}

impl Iterable for PyByteArray {
Expand Down
38 changes: 34 additions & 4 deletions vm/src/builtins/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ use crate::{
},
common::hash::PyHash,
function::{ArgBytesLike, ArgIterable, OptionalArg, OptionalOption},
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn},
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods},
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,
Expand Down Expand Up @@ -103,7 +103,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)]
Expand Down Expand Up @@ -540,6 +540,36 @@ impl BufferInternal for PyRef<PyBytes> {
fn retain(&self) {}
}

impl AsMapping for PyBytes {
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
Ok(PyMappingMethods {
length: Some(Self::length),
subscript: Some(Self::subscript),
ass_subscript: None,
})
}

#[inline]
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
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))?
}

#[cold]
fn ass_subscript(
zelf: PyObjectRef,
_needle: PyObjectRef,
_value: Option<PyObjectRef>,
_vm: &VirtualMachine,
) -> PyResult<()> {
unreachable!("ass_subscript not implemented for {}", zelf.class())
}
}

impl Hashable for PyBytes {
fn hash(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyHash> {
Ok(zelf.inner.hash(vm))
Expand Down
67 changes: 39 additions & 28 deletions vm/src/builtins/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ use crate::{
common::ascii,
dictdatatype::{self, DictKey},
function::{ArgIterable, FuncArgs, KwArgs, OptionalArg},
protocol::PyIterReturn,
protocol::{PyIterReturn, PyMappingMethods},
slots::{
Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, Unhashable,
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator,
Unhashable,
},
vm::{ReprGuard, VirtualMachine},
IdProtocol, IntoPyObject, ItemProtocol,
PyArithmeticValue::*,
PyAttributes, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef,
PyResult, PyValue, TryFromObject, TypeProtocol,
PyResult, PyValue, TypeProtocol,
};
use crossbeam_utils::atomic::AtomicCell;
use std::fmt;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -410,6 +411,39 @@ impl PyDict {
}
}

impl AsMapping for PyDict {
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
Ok(PyMappingMethods {
length: Some(Self::length),
subscript: Some(Self::subscript),
ass_subscript: Some(Self::ass_subscript),
})
}

#[inline]
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
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: Option<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
Self::downcast_ref(&zelf, vm).map(|zelf| match value {
Some(value) => zelf.setitem(needle, value, vm),
None => zelf.delitem(needle, vm),
})?
}
}

impl Comparable for PyDict {
fn cmp(
zelf: &PyRef<Self>,
Expand Down Expand Up @@ -651,7 +685,7 @@ macro_rules! dict_iterator {
}

impl $name {
fn new(dict: PyDictRef) -> Self {
pub fn new(dict: PyDictRef) -> Self {
$name { dict }
}
}
Expand Down Expand Up @@ -901,26 +935,3 @@ pub(crate) fn init(context: &PyContext) {
PyDictItemIterator::extend_class(context, &context.types.dict_itemiterator_type);
PyDictReverseItemIterator::extend_class(context, &context.types.dict_reverseitemiterator_type);
}

pub struct PyMapping {
dict: PyDictRef,
}

impl TryFromObject for PyMapping {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let dict = vm.ctx.new_dict();
PyDict::merge(
&dict.entries,
OptionalArg::Present(obj),
KwArgs::default(),
vm,
)?;
Ok(PyMapping { dict })
}
}

impl PyMapping {
pub fn into_dict(self) -> PyDictRef {
self.dict
}
}
44 changes: 39 additions & 5 deletions vm/src/builtins/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ use crate::common::lock::{
};
use crate::{
function::{ArgIterable, FuncArgs, OptionalArg},
protocol::PyIterReturn,
protocol::{PyIterReturn, PyMappingMethods},
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},
Expand Down Expand Up @@ -82,7 +83,7 @@ pub(crate) struct SortOptions {

pub type PyListRef = PyRef<PyList>;

#[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) {
Expand Down Expand Up @@ -353,8 +354,8 @@ impl PyList {
}

#[pymethod(magic)]
fn delitem(&self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
match subscript {
fn delitem(&self, subscript: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
match SequenceIndex::try_from_object_for(vm, subscript, Self::NAME)? {
SequenceIndex::Int(index) => self.delindex(index, vm),
SequenceIndex::Slice(slice) => self.delslice(slice, vm),
}
Expand Down Expand Up @@ -416,6 +417,39 @@ impl PyList {
}
}

impl AsMapping for PyList {
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
Ok(PyMappingMethods {
length: Some(Self::length),
subscript: Some(Self::subscript),
ass_subscript: Some(Self::ass_subscript),
})
}

#[inline]
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
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: Option<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
Self::downcast_ref(&zelf, vm).map(|zelf| match value {
Some(value) => zelf.setitem(needle, value, vm),
None => zelf.delitem(needle, vm),
})?
}
}

impl Iterable for PyList {
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
Ok(PyListIterator {
Expand Down
Loading