Skip to content

Commit 6b1af9a

Browse files
authored
Merge pull request #3121 from Snowapril/mapping-protocol
Implement Mapping Protocol
2 parents 843a1bb + 7b0965c commit 6b1af9a

16 files changed

Lines changed: 673 additions & 98 deletions

File tree

‎stdlib/src/array.rs‎

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ mod array {
1717
},
1818
class_or_notimplemented,
1919
function::{ArgBytesLike, ArgIterable, OptionalArg},
20-
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard},
20+
protocol::{
21+
BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods, ResizeGuard,
22+
},
2123
sliceable::{saturate_index, PySliceableSequence, PySliceableSequenceMut, SequenceIndex},
2224
slots::{
23-
AsBuffer, Comparable, Iterable, IteratorIterable, PyComparisonOp, SlotConstructor,
24-
SlotIterator,
25+
AsBuffer, AsMapping, Comparable, Iterable, IteratorIterable, PyComparisonOp,
26+
SlotConstructor, SlotIterator,
2527
},
2628
IdProtocol, IntoPyObject, IntoPyResult, PyComparisonValue, PyObjectRef, PyRef, PyResult,
2729
PyValue, TryFromObject, TypeProtocol, VirtualMachine,
@@ -665,7 +667,10 @@ mod array {
665667
}
666668
}
667669

668-
#[pyimpl(flags(BASETYPE), with(Comparable, AsBuffer, Iterable, SlotConstructor))]
670+
#[pyimpl(
671+
flags(BASETYPE),
672+
with(Comparable, AsBuffer, AsMapping, Iterable, SlotConstructor)
673+
)]
669674
impl PyArray {
670675
fn read(&self) -> PyRwLockReadGuard<'_, ArrayContentType> {
671676
self.array.read()
@@ -1161,6 +1166,38 @@ mod array {
11611166
}
11621167
}
11631168

1169+
impl AsMapping for PyArray {
1170+
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
1171+
Ok(PyMappingMethods {
1172+
length: Some(Self::length),
1173+
subscript: Some(Self::subscript),
1174+
ass_subscript: Some(Self::ass_subscript),
1175+
})
1176+
}
1177+
1178+
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
1179+
Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))?
1180+
}
1181+
1182+
fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1183+
Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))?
1184+
}
1185+
1186+
fn ass_subscript(
1187+
zelf: PyObjectRef,
1188+
needle: PyObjectRef,
1189+
value: Option<PyObjectRef>,
1190+
vm: &VirtualMachine,
1191+
) -> PyResult<()> {
1192+
match value {
1193+
Some(value) => {
1194+
Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))?
1195+
}
1196+
None => Self::downcast(zelf, vm).map(|zelf| Self::delitem(zelf, needle, vm))?,
1197+
}
1198+
}
1199+
}
1200+
11641201
impl Iterable for PyArray {
11651202
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
11661203
Ok(PyArrayIter {

‎vm/src/builtins/bytearray.rs‎

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ use crate::{
1717
ByteInnerTranslateOptions, DecodeArgs, PyBytesInner,
1818
},
1919
function::{ArgBytesLike, ArgIterable, FuncArgs, OptionalArg, OptionalOption},
20-
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard},
20+
protocol::{
21+
BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods, ResizeGuard,
22+
},
2123
sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex},
2224
slots::{
23-
AsBuffer, Callable, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp,
24-
SlotIterator, Unhashable,
25+
AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable,
26+
PyComparisonOp, SlotIterator, Unhashable,
2527
},
2628
utils::Either,
2729
IdProtocol, IntoPyObject, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef,
@@ -97,7 +99,10 @@ pub(crate) fn init(context: &PyContext) {
9799
PyByteArrayIterator::extend_class(context, &context.types.bytearray_iterator_type);
98100
}
99101

100-
#[pyimpl(flags(BASETYPE), with(Hashable, Comparable, AsBuffer, Iterable))]
102+
#[pyimpl(
103+
flags(BASETYPE),
104+
with(Hashable, Comparable, AsBuffer, AsMapping, Iterable)
105+
)]
101106
impl PyByteArray {
102107
#[pyslot]
103108
fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
@@ -203,9 +208,9 @@ impl PyByteArray {
203208
}
204209

205210
#[pymethod(magic)]
206-
pub fn delitem(&self, needle: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
211+
pub fn delitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
207212
let elements = &mut self.try_resizable(vm)?.elements;
208-
match needle {
213+
match SequenceIndex::try_from_object_for(vm, needle, Self::NAME)? {
209214
SequenceIndex::Int(int) => {
210215
if let Some(idx) = elements.wrap_index(int) {
211216
elements.remove(idx);
@@ -714,6 +719,41 @@ impl<'a> ResizeGuard<'a> for PyByteArray {
714719
}
715720
}
716721

722+
impl AsMapping for PyByteArray {
723+
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
724+
Ok(PyMappingMethods {
725+
length: Some(Self::length),
726+
subscript: Some(Self::subscript),
727+
ass_subscript: Some(Self::ass_subscript),
728+
})
729+
}
730+
731+
#[inline]
732+
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
733+
Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))?
734+
}
735+
736+
#[inline]
737+
fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
738+
Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))?
739+
}
740+
741+
#[inline]
742+
fn ass_subscript(
743+
zelf: PyObjectRef,
744+
needle: PyObjectRef,
745+
value: Option<PyObjectRef>,
746+
vm: &VirtualMachine,
747+
) -> PyResult<()> {
748+
match value {
749+
Some(value) => {
750+
Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))
751+
}
752+
None => Self::downcast_ref(&zelf, vm).map(|zelf| zelf.delitem(needle, vm)),
753+
}?
754+
}
755+
}
756+
717757
impl Unhashable for PyByteArray {}
718758

719759
impl Iterable for PyByteArray {

‎vm/src/builtins/bytes.rs‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use crate::{
77
},
88
common::hash::PyHash,
99
function::{ArgBytesLike, ArgIterable, OptionalArg, OptionalOption},
10-
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn},
10+
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods},
1111
slots::{
12-
AsBuffer, Callable, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp,
13-
SlotConstructor, SlotIterator,
12+
AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable,
13+
PyComparisonOp, SlotConstructor, SlotIterator,
1414
},
1515
utils::Either,
1616
IdProtocol, IntoPyObject, IntoPyResult, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef,
@@ -105,7 +105,7 @@ impl SlotConstructor for PyBytes {
105105

106106
#[pyimpl(
107107
flags(BASETYPE),
108-
with(Hashable, Comparable, AsBuffer, Iterable, SlotConstructor)
108+
with(AsMapping, Hashable, Comparable, AsBuffer, Iterable, SlotConstructor)
109109
)]
110110
impl PyBytes {
111111
#[pymethod(magic)]
@@ -542,6 +542,36 @@ impl BufferInternal for PyRef<PyBytes> {
542542
fn retain(&self) {}
543543
}
544544

545+
impl AsMapping for PyBytes {
546+
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
547+
Ok(PyMappingMethods {
548+
length: Some(Self::length),
549+
subscript: Some(Self::subscript),
550+
ass_subscript: None,
551+
})
552+
}
553+
554+
#[inline]
555+
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
556+
Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))?
557+
}
558+
559+
#[inline]
560+
fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
561+
Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))?
562+
}
563+
564+
#[cold]
565+
fn ass_subscript(
566+
zelf: PyObjectRef,
567+
_needle: PyObjectRef,
568+
_value: Option<PyObjectRef>,
569+
_vm: &VirtualMachine,
570+
) -> PyResult<()> {
571+
unreachable!("ass_subscript not implemented for {}", zelf.class())
572+
}
573+
}
574+
545575
impl Hashable for PyBytes {
546576
fn hash(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyHash> {
547577
Ok(zelf.inner.hash(vm))

‎vm/src/builtins/dict.rs‎

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ use crate::{
44
common::ascii,
55
dictdatatype::{self, DictKey},
66
function::{ArgIterable, FuncArgs, KwArgs, OptionalArg},
7-
protocol::PyIterReturn,
7+
protocol::{PyIterReturn, PyMappingMethods},
88
slots::{
9-
Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, Unhashable,
9+
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator,
10+
Unhashable,
1011
},
1112
vm::{ReprGuard, VirtualMachine},
1213
IdProtocol, IntoPyObject, ItemProtocol,
1314
PyArithmeticValue::*,
1415
PyAttributes, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef,
15-
PyResult, PyValue, TryFromObject, TypeProtocol,
16+
PyResult, PyValue, TypeProtocol,
1617
};
1718
use rustpython_common::lock::PyMutex;
1819
use std::fmt;
@@ -51,7 +52,7 @@ impl PyValue for PyDict {
5152

5253
// Python dict methods:
5354
#[allow(clippy::len_without_is_empty)]
54-
#[pyimpl(with(Hashable, Comparable, Iterable), flags(BASETYPE))]
55+
#[pyimpl(with(AsMapping, Hashable, Comparable, Iterable), flags(BASETYPE))]
5556
impl PyDict {
5657
#[pyslot]
5758
fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
@@ -410,6 +411,39 @@ impl PyDict {
410411
}
411412
}
412413

414+
impl AsMapping for PyDict {
415+
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
416+
Ok(PyMappingMethods {
417+
length: Some(Self::length),
418+
subscript: Some(Self::subscript),
419+
ass_subscript: Some(Self::ass_subscript),
420+
})
421+
}
422+
423+
#[inline]
424+
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
425+
Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))?
426+
}
427+
428+
#[inline]
429+
fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
430+
Self::downcast(zelf, vm).map(|zelf| Self::getitem(zelf, needle, vm))?
431+
}
432+
433+
#[inline]
434+
fn ass_subscript(
435+
zelf: PyObjectRef,
436+
needle: PyObjectRef,
437+
value: Option<PyObjectRef>,
438+
vm: &VirtualMachine,
439+
) -> PyResult<()> {
440+
Self::downcast_ref(&zelf, vm).map(|zelf| match value {
441+
Some(value) => zelf.setitem(needle, value, vm),
442+
None => zelf.delitem(needle, vm),
443+
})?
444+
}
445+
}
446+
413447
impl Comparable for PyDict {
414448
fn cmp(
415449
zelf: &PyRef<Self>,
@@ -653,7 +687,7 @@ macro_rules! dict_iterator {
653687
}
654688

655689
impl $name {
656-
fn new(dict: PyDictRef) -> Self {
690+
pub fn new(dict: PyDictRef) -> Self {
657691
$name { dict }
658692
}
659693
}
@@ -897,26 +931,3 @@ pub(crate) fn init(context: &PyContext) {
897931
PyDictItemIterator::extend_class(context, &context.types.dict_itemiterator_type);
898932
PyDictReverseItemIterator::extend_class(context, &context.types.dict_reverseitemiterator_type);
899933
}
900-
901-
pub struct PyMapping {
902-
dict: PyDictRef,
903-
}
904-
905-
impl TryFromObject for PyMapping {
906-
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
907-
let dict = vm.ctx.new_dict();
908-
PyDict::merge(
909-
&dict.entries,
910-
OptionalArg::Present(obj),
911-
KwArgs::default(),
912-
vm,
913-
)?;
914-
Ok(PyMapping { dict })
915-
}
916-
}
917-
918-
impl PyMapping {
919-
pub fn into_dict(self) -> PyDictRef {
920-
self.dict
921-
}
922-
}

‎vm/src/builtins/list.rs‎

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use crate::common::lock::{
44
};
55
use crate::{
66
function::{ArgIterable, FuncArgs, OptionalArg},
7-
protocol::PyIterReturn,
7+
protocol::{PyIterReturn, PyMappingMethods},
88
sequence::{self, SimpleSeq},
99
sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex},
1010
slots::{
11-
Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, Unhashable,
11+
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator,
12+
Unhashable,
1213
},
1314
utils::Either,
1415
vm::{ReprGuard, VirtualMachine},
@@ -77,7 +78,7 @@ pub(crate) struct SortOptions {
7778

7879
pub type PyListRef = PyRef<PyList>;
7980

80-
#[pyimpl(with(Iterable, Hashable, Comparable), flags(BASETYPE))]
81+
#[pyimpl(with(AsMapping, Iterable, Hashable, Comparable), flags(BASETYPE))]
8182
impl PyList {
8283
#[pymethod]
8384
pub(crate) fn append(&self, x: PyObjectRef) {
@@ -341,8 +342,8 @@ impl PyList {
341342
}
342343

343344
#[pymethod(magic)]
344-
fn delitem(&self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
345-
match subscript {
345+
fn delitem(&self, subscript: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
346+
match SequenceIndex::try_from_object_for(vm, subscript, Self::NAME)? {
346347
SequenceIndex::Int(index) => self.delindex(index, vm),
347348
SequenceIndex::Slice(slice) => self.delslice(slice, vm),
348349
}
@@ -404,6 +405,39 @@ impl PyList {
404405
}
405406
}
406407

408+
impl AsMapping for PyList {
409+
fn as_mapping(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyMappingMethods> {
410+
Ok(PyMappingMethods {
411+
length: Some(Self::length),
412+
subscript: Some(Self::subscript),
413+
ass_subscript: Some(Self::ass_subscript),
414+
})
415+
}
416+
417+
#[inline]
418+
fn length(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
419+
Self::downcast_ref(&zelf, vm).map(|zelf| Ok(zelf.len()))?
420+
}
421+
422+
#[inline]
423+
fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
424+
Self::downcast(zelf, vm).map(|zelf| Self::getitem(zelf, needle, vm))?
425+
}
426+
427+
#[inline]
428+
fn ass_subscript(
429+
zelf: PyObjectRef,
430+
needle: PyObjectRef,
431+
value: Option<PyObjectRef>,
432+
vm: &VirtualMachine,
433+
) -> PyResult<()> {
434+
Self::downcast_ref(&zelf, vm).map(|zelf| match value {
435+
Some(value) => zelf.setitem(needle, value, vm),
436+
None => zelf.delitem(needle, vm),
437+
})?
438+
}
439+
}
440+
407441
impl Iterable for PyList {
408442
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
409443
Ok(PyListIterator {

0 commit comments

Comments
 (0)