From 14ce6aa49a96ad3b4076452bebe7c43409963e55 Mon Sep 17 00:00:00 2001 From: snowapril Date: Tue, 21 Sep 2021 00:10:24 +0900 Subject: [PATCH 01/14] add slot_as_mapping slots with atomic cell --- vm/src/slots.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/vm/src/slots.rs b/vm/src/slots.rs index 37382e6ecd8..f2b66804337 100644 --- a/vm/src/slots.rs +++ b/vm/src/slots.rs @@ -1,4 +1,4 @@ -use crate::builtins::{PyStrRef, PyTypeRef}; +use crate::builtins::{dict::PyMapping, PyStrRef, PyTypeRef}; use crate::common::hash::PyHash; use crate::common::lock::PyRwLock; use crate::function::{FromArgs, FuncArgs, OptionalArg}; @@ -70,6 +70,7 @@ pub(crate) type GetattroFunc = fn(PyObjectRef, PyStrRef, &VirtualMachine) -> PyR pub(crate) type SetattroFunc = fn(&PyObjectRef, PyStrRef, Option, &VirtualMachine) -> PyResult<()>; pub(crate) type BufferFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult; +pub(crate) type MappingFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult; pub(crate) type IterFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult; pub(crate) type IterNextFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult; @@ -85,7 +86,7 @@ pub struct PyTypeSlots { // Method suites for standard classes // tp_as_number // tp_as_sequence - // tp_as_mapping + pub as_mapping: AtomicCell>, // More standard operations (here for binary compatibility) pub hash: AtomicCell>, @@ -532,6 +533,19 @@ pub trait AsBuffer: PyValue { fn as_buffer(zelf: &PyRef, vm: &VirtualMachine) -> PyResult; } +#[pyimpl] +pub trait AsMapping: PyValue { + #[pyslot] + fn slot_as_mapping(zelf: &PyObjectRef, vm: &VirtualMachine) -> PyResult { + let zelf = zelf + .downcast_ref() + .ok_or_else(|| vm.new_type_error("unexpected payload for as_mapping".to_owned()))?; + Self::as_mapping(zelf, vm) + } + + fn as_mapping(zelf: &PyRef, vm: &VirtualMachine) -> PyResult; +} + #[pyimpl] pub trait Iterable: PyValue { #[pyslot] From 77351b3da86baeb66062a954dcc501255dcec0da Mon Sep 17 00:00:00 2001 From: snowapril Date: Tue, 21 Sep 2021 00:12:26 +0900 Subject: [PATCH 02/14] add PyMapping struct for mapping protocol --- vm/src/builtins/dict.rs | 36 +++++++++++++++++++----------------- vm/src/slots.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index c35b100c76f..a65dc47a7f4 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -12,7 +12,7 @@ use crate::{ IdProtocol, IntoPyObject, ItemProtocol, PyArithmeticValue::*, PyAttributes, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, - PyResult, PyValue, TryFromObject, TypeProtocol, + PyResult, PyValue, TryFromBorrowedObject, TypeProtocol, }; use crossbeam_utils::atomic::AtomicCell; use std::fmt; @@ -902,25 +902,27 @@ pub(crate) fn init(context: &PyContext) { PyDictReverseItemIterator::extend_class(context, &context.types.dict_reverseitemiterator_type); } +#[allow(clippy::type_complexity)] pub struct PyMapping { - dict: PyDictRef, + pub length: Option PyResult>, + pub subscript: Option PyResult>, + pub ass_subscript: + Option PyResult<()>>, } -impl TryFromObject for PyMapping { - fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - let dict = vm.ctx.new_dict(); - PyDict::merge( - &dict.entries, - OptionalArg::Present(obj), - KwArgs::default(), - vm, - )?; - Ok(PyMapping { dict }) - } -} +impl PyMapping {} -impl PyMapping { - pub fn into_dict(self) -> PyDictRef { - self.dict +impl TryFromBorrowedObject for PyMapping { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { + let obj_cls = obj.class(); + for cls in obj_cls.iter_mro() { + if let Some(f) = cls.slots.as_mapping.load() { + return f(obj, vm); + } + } + Err(vm.new_type_error(format!( + "a dict-like object is required, not '{}'", + obj_cls.name() + ))) } } diff --git a/vm/src/slots.rs b/vm/src/slots.rs index f2b66804337..c63e1b14485 100644 --- a/vm/src/slots.rs +++ b/vm/src/slots.rs @@ -543,7 +543,38 @@ pub trait AsMapping: PyValue { Self::as_mapping(zelf, vm) } + fn downcast(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult> { + zelf.downcast::().map_err(|obj| { + vm.new_type_error(format!( + "{} type is required, not {}", + Self::class(vm), + obj.class() + )) + }) + } + + fn downcast_ref<'a>(zelf: &'a PyObjectRef, vm: &VirtualMachine) -> PyResult<&'a PyRef> { + zelf.downcast_ref::().ok_or_else(|| { + vm.new_type_error(format!( + "{} type is required, not {}", + Self::class(vm), + zelf.class() + )) + }) + } + fn as_mapping(zelf: &PyRef, vm: &VirtualMachine) -> PyResult; + + fn length(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult; + + fn subscript(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult; + + fn ass_subscript( + zelf: PyObjectRef, + needle: PyObjectRef, + value: PyObjectRef, + vm: &VirtualMachine, + ) -> PyResult<()>; } #[pyimpl] From 1b6cdf507e4f8307862a67194fe41e54407ddc99 Mon Sep 17 00:00:00 2001 From: snowapril Date: Tue, 21 Sep 2021 00:13:48 +0900 Subject: [PATCH 03/14] rename length to compute_length As cpython use `range_compute_length` naming and `length` can be conflict with mapping protocol's method --- vm/src/builtins/range.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 4f6db0a594c..d9e88b66786 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -98,7 +98,7 @@ impl PyRange { #[inline] pub fn is_empty(&self) -> bool { - self.length().is_zero() + self.compute_length().is_zero() } #[inline] @@ -116,7 +116,7 @@ impl PyRange { } if index.is_negative() { - let length = self.length(); + let length = self.compute_length(); let index: BigInt = &length + index; if index.is_negative() { return None; @@ -143,7 +143,7 @@ impl PyRange { } #[inline] - fn length(&self) -> BigInt { + fn compute_length(&self) -> BigInt { let start = self.start.as_bigint(); let stop = self.stop.as_bigint(); let step = self.step.as_bigint(); @@ -251,7 +251,7 @@ impl PyRange { #[pymethod(magic)] fn len(&self) -> BigInt { - self.length() + self.compute_length() } #[pymethod(magic)] @@ -335,7 +335,7 @@ impl PyRange { match subscript { RangeIndex::Slice(slice) => { let (mut substart, mut substop, mut substep) = - slice.inner_indices(&self.length(), vm)?; + slice.inner_indices(&self.compute_length(), vm)?; let range_step = &self.step; let range_start = &self.start; @@ -374,7 +374,7 @@ impl PyRange { impl Hashable for PyRange { fn hash(zelf: &PyRef, vm: &VirtualMachine) -> PyResult { - let length = zelf.length(); + let length = zelf.compute_length(); let elements = if length.is_zero() { [vm.ctx.new_int(length), vm.ctx.none(), vm.ctx.none()] } else if length.is_one() { @@ -406,8 +406,8 @@ impl Comparable for PyRange { return Ok(true.into()); } let rhs = class_or_notimplemented!(Self, other); - let lhs_len = zelf.length(); - let eq = if lhs_len != rhs.length() { + let lhs_len = zelf.compute_length(); + let eq = if lhs_len != rhs.compute_length() { false } else if lhs_len.is_zero() { true From fc761b4e5b980aecb96ab4e81c273c793a2c5238 Mon Sep 17 00:00:00 2001 From: snowapril Date: Tue, 21 Sep 2021 00:14:32 +0900 Subject: [PATCH 04/14] add mapping protocol to proper types --- stdlib/src/array.rs | 40 ++++++++++++++++++++++++++++----- vm/src/builtins/bytearray.rs | 40 ++++++++++++++++++++++++++++++--- vm/src/builtins/bytes.rs | 37 +++++++++++++++++++++++++++--- vm/src/builtins/dict.rs | 35 +++++++++++++++++++++++++++-- vm/src/builtins/list.rs | 36 +++++++++++++++++++++++++++-- vm/src/builtins/mappingproxy.rs | 38 ++++++++++++++++++++++++++++--- vm/src/builtins/memory.rs | 38 +++++++++++++++++++++++++++++-- vm/src/builtins/range.rs | 38 +++++++++++++++++++++++++++++-- vm/src/builtins/tuple.rs | 40 ++++++++++++++++++++++++++++++--- 9 files changed, 317 insertions(+), 25 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 29a675e110f..4cd11b920ba 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 2ab6091dcda..4dd908a7295 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 2df6000179c..5cfe2858810 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 a65dc47a7f4..efb4f2cc4eb 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 1f0fdfad587..deeaecf0a6c 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 fcf7d907163..b8e080cf6d9 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 eaf8539c77f..e2180f778b3 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 d9e88b66786..2b24010846a 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 03c11d4e506..bb662140ccd 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) From e83b68b810d66ce4837cc3fbb1e3b06e1abb709d Mon Sep 17 00:00:00 2001 From: snowapril Date: Tue, 21 Sep 2021 00:14:49 +0900 Subject: [PATCH 05/14] apply mapping protocol in itemprotocol --- vm/src/pyobject.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 514a88823a7..deb43ce5260 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -10,6 +10,7 @@ use crate::{ builtinfunc::PyNativeFuncDef, bytearray, bytes, code::{self, PyCode}, + dict::PyMapping, getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetSet}, namespace::PyNamespace, object, pystr, @@ -639,6 +640,12 @@ where T: IntoPyObject, { fn get_item(&self, key: T, vm: &VirtualMachine) -> PyResult { + if let Ok(map) = PyMapping::try_from_borrowed_object(vm, self) { + if let Some(getitem) = map.subscript { + return getitem(self.clone(), key.into_pyobject(vm), vm); + } + } + match vm.get_special_method(self.clone(), "__getitem__")? { Ok(special_method) => return special_method.invoke((key,), vm), Err(obj) => { @@ -656,6 +663,12 @@ where } fn set_item(&self, key: T, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + if let Ok(map) = PyMapping::try_from_borrowed_object(vm, self) { + if let Some(setitem) = map.ass_subscript { + return setitem(self.clone(), key.into_pyobject(vm), value, vm); + } + } + vm.get_special_method(self.clone(), "__setitem__")? .map_err(|obj| { vm.new_type_error(format!( From b197a178ead158ae78a402347da8225c8f90b049 Mon Sep 17 00:00:00 2001 From: snowapril Date: Wed, 22 Sep 2021 18:46:30 +0900 Subject: [PATCH 06/14] switch RangeIndex to PyObjectRef As `getitem` method in other types, get second argument as PyObjectRef. --- vm/src/builtins/range.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 2b24010846a..df601bf1a6e 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -334,8 +334,8 @@ impl PyRange { } #[pymethod(magic)] - fn getitem(&self, subscript: RangeIndex, vm: &VirtualMachine) -> PyResult { - match subscript { + fn getitem(&self, subscript: PyObjectRef, vm: &VirtualMachine) -> PyResult { + match RangeIndex::try_from_object(vm, subscript)? { RangeIndex::Slice(slice) => { let (mut substart, mut substop, mut substep) = slice.inner_indices(&self.compute_length(), vm)?; @@ -391,8 +391,7 @@ impl AsMapping for PyRange { #[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))? + Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))? } #[inline] From 4f009ef9712fe7c95a5bc364fe48931909807f3d Mon Sep 17 00:00:00 2001 From: snowapril Date: Wed, 22 Sep 2021 18:46:53 +0900 Subject: [PATCH 07/14] switch SequenceIndex to PyObjectRef As `getitem` and `setitem methods in other types, get second argument as PyObjectRef. --- vm/src/builtins/memory.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index e2180f778b3..d25c3d32d12 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -14,8 +14,8 @@ use crate::{ slots::{AsBuffer, AsMapping, Comparable, Hashable, PyComparisonOp, SlotConstructor}, stdlib::pystruct::FormatSpec, utils::Either, - IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, - PyResult, PyValue, TryFromBorrowedObject, TryFromObject, TypeProtocol, VirtualMachine, + IdProtocol, IntoPyObject, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, + PyRef, PyResult, PyValue, TryFromBorrowedObject, TryFromObject, TypeProtocol, VirtualMachine, }; use crossbeam_utils::atomic::AtomicCell; use itertools::Itertools; @@ -343,10 +343,10 @@ impl PyMemoryView { } #[pymethod(magic)] - fn getitem(zelf: PyRef, needle: SequenceIndex, vm: &VirtualMachine) -> PyResult { + fn getitem(zelf: PyRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { zelf.try_not_released(vm)?; - match needle { - SequenceIndex::Int(i) => Self::getitem_by_idx(zelf, i, vm), + match SequenceIndex::try_from_object_for(vm, needle, Self::NAME)? { + SequenceIndex::Int(index) => Self::getitem_by_idx(zelf, index, vm), SequenceIndex::Slice(slice) => Self::getitem_by_slice(zelf, slice, vm), } } @@ -460,7 +460,7 @@ impl PyMemoryView { #[pymethod(magic)] fn setitem( zelf: PyRef, - needle: SequenceIndex, + needle: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { @@ -468,8 +468,8 @@ impl PyMemoryView { if zelf.buffer.options.readonly { return Err(vm.new_type_error("cannot modify read-only memory".to_owned())); } - match needle { - SequenceIndex::Int(i) => Self::setitem_by_idx(zelf, i, value, vm), + match SequenceIndex::try_from_object_for(vm, needle, Self::NAME)? { + SequenceIndex::Int(index) => Self::setitem_by_idx(zelf, index, value, vm), SequenceIndex::Slice(slice) => Self::setitem_by_slice(zelf, slice, value, vm), } } @@ -751,8 +751,7 @@ impl AsMapping for PyMemoryView { #[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))? + Self::downcast(zelf, vm).map(|zelf| Self::getitem(zelf, needle, vm))? } #[inline] @@ -762,9 +761,7 @@ impl AsMapping for PyMemoryView { value: PyObjectRef, vm: &VirtualMachine, ) -> PyResult<()> { - Self::downcast(zelf, vm).map(|zelf| { - Self::setitem(zelf, SequenceIndex::try_from_object(vm, needle)?, value, vm) - })? + Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))? } } From 1fbbdaabe396483c01f0b4496b9c8648206261c7 Mon Sep 17 00:00:00 2001 From: snowapril Date: Wed, 22 Sep 2021 19:46:45 +0900 Subject: [PATCH 08/14] support delitem in ass_subscript --- stdlib/src/array.rs | 9 +++++++-- vm/src/builtins/bytearray.rs | 13 +++++++++---- vm/src/builtins/bytes.rs | 2 +- vm/src/builtins/dict.rs | 9 ++++++--- vm/src/builtins/list.rs | 11 +++++++---- vm/src/builtins/mappingproxy.rs | 2 +- vm/src/builtins/memory.rs | 9 +++++++-- vm/src/builtins/range.rs | 2 +- vm/src/builtins/tuple.rs | 2 +- vm/src/pyobject.rs | 8 +++++++- vm/src/slots.rs | 2 +- 11 files changed, 48 insertions(+), 21 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 4cd11b920ba..6984455aa8c 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -1184,10 +1184,15 @@ mod array { fn ass_subscript( zelf: PyObjectRef, needle: PyObjectRef, - value: PyObjectRef, + value: Option, vm: &VirtualMachine, ) -> PyResult<()> { - Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))? + 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))?, + } } } diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 4dd908a7295..77139f93f90 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -205,9 +205,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); @@ -739,10 +739,15 @@ impl AsMapping for PyByteArray { fn ass_subscript( zelf: PyObjectRef, needle: PyObjectRef, - value: PyObjectRef, + value: Option, vm: &VirtualMachine, ) -> PyResult<()> { - Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))? + 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)), + }? } } diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 5cfe2858810..783763cc186 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -564,7 +564,7 @@ impl AsMapping for PyBytes { fn ass_subscript( zelf: PyObjectRef, _needle: PyObjectRef, - _value: PyObjectRef, + _value: Option, _vm: &VirtualMachine, ) -> PyResult<()> { unreachable!("ass_subscript not implemented for {}", zelf.class()) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index efb4f2cc4eb..f4664b5d8a3 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -434,10 +434,13 @@ impl AsMapping for PyDict { fn ass_subscript( zelf: PyObjectRef, needle: PyObjectRef, - value: PyObjectRef, + value: Option, vm: &VirtualMachine, ) -> PyResult<()> { - Self::downcast_ref(&zelf, vm).map(|zelf| zelf.setitem(needle, value, vm))? + Self::downcast_ref(&zelf, vm).map(|zelf| match value { + Some(value) => zelf.setitem(needle, value, vm), + None => zelf.delitem(needle, vm), + })? } } @@ -938,7 +941,7 @@ pub struct PyMapping { pub length: Option PyResult>, pub subscript: Option PyResult>, pub ass_subscript: - Option PyResult<()>>, + Option, &VirtualMachine) -> PyResult<()>>, } impl PyMapping {} diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index deeaecf0a6c..e80d10e2bbe 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -355,8 +355,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), } @@ -441,10 +441,13 @@ impl AsMapping for PyList { fn ass_subscript( zelf: PyObjectRef, needle: PyObjectRef, - value: PyObjectRef, + value: Option, vm: &VirtualMachine, ) -> PyResult<()> { - Self::downcast_ref(&zelf, vm).map(|zelf| zelf.setitem(needle, value, vm))? + Self::downcast_ref(&zelf, vm).map(|zelf| match value { + Some(value) => zelf.setitem(needle, value, vm), + None => zelf.delitem(needle, vm), + })? } } diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index b8e080cf6d9..6c63fecec42 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -152,7 +152,7 @@ impl AsMapping for PyMappingProxy { fn ass_subscript( zelf: PyObjectRef, _needle: PyObjectRef, - _value: PyObjectRef, + _value: Option, _vm: &VirtualMachine, ) -> PyResult<()> { unreachable!("ass_subscript not implemented for {}", zelf.class()) diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index d25c3d32d12..4b682ddc256 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -758,10 +758,15 @@ impl AsMapping for PyMemoryView { fn ass_subscript( zelf: PyObjectRef, needle: PyObjectRef, - value: PyObjectRef, + value: Option, vm: &VirtualMachine, ) -> PyResult<()> { - Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))? + match value { + Some(value) => { + Self::downcast(zelf, vm).map(|zelf| Self::setitem(zelf, needle, value, vm))? + } + None => Err(vm.new_type_error("cannot delete memory".to_owned())), + } } } diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index df601bf1a6e..66187c6fa25 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -398,7 +398,7 @@ impl AsMapping for PyRange { fn ass_subscript( zelf: PyObjectRef, _needle: PyObjectRef, - _value: PyObjectRef, + _value: Option, _vm: &VirtualMachine, ) -> PyResult<()> { unreachable!("ass_subscript not implemented for {}", zelf.class()) diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index bb662140ccd..1dab3a0e9a0 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -311,7 +311,7 @@ impl AsMapping for PyTuple { fn ass_subscript( zelf: PyObjectRef, _needle: PyObjectRef, - _value: PyObjectRef, + _value: Option, _vm: &VirtualMachine, ) -> PyResult<()> { unreachable!("ass_subscript not implemented for {}", zelf.class()) diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index deb43ce5260..e268f320482 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -665,7 +665,7 @@ where fn set_item(&self, key: T, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { if let Ok(map) = PyMapping::try_from_borrowed_object(vm, self) { if let Some(setitem) = map.ass_subscript { - return setitem(self.clone(), key.into_pyobject(vm), value, vm); + return setitem(self.clone(), key.into_pyobject(vm), Some(value), vm); } } @@ -681,6 +681,12 @@ where } fn del_item(&self, key: T, vm: &VirtualMachine) -> PyResult<()> { + if let Ok(map) = PyMapping::try_from_borrowed_object(vm, self) { + if let Some(setitem) = map.ass_subscript { + return setitem(self.clone(), key.into_pyobject(vm), None, vm); + } + } + vm.get_special_method(self.clone(), "__delitem__")? .map_err(|obj| { vm.new_type_error(format!( diff --git a/vm/src/slots.rs b/vm/src/slots.rs index c63e1b14485..e5c5e7b2297 100644 --- a/vm/src/slots.rs +++ b/vm/src/slots.rs @@ -572,7 +572,7 @@ pub trait AsMapping: PyValue { fn ass_subscript( zelf: PyObjectRef, needle: PyObjectRef, - value: PyObjectRef, + value: Option, vm: &VirtualMachine, ) -> PyResult<()>; } From 6e11b8931c31c346e26eb482271aec7d1c140374 Mon Sep 17 00:00:00 2001 From: snowapril Date: Wed, 29 Sep 2021 14:09:16 +0900 Subject: [PATCH 09/14] add mapping protocol methods to update_slot Signed-off-by: snowapril --- vm/src/builtins/pytype.rs | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/pytype.rs index b9f67d096d9..4415c95dd3b 100644 --- a/vm/src/builtins/pytype.rs +++ b/vm/src/builtins/pytype.rs @@ -4,6 +4,7 @@ use super::{ }; use crate::common::{ascii, lock::PyRwLock}; use crate::{ + builtins::dict::PyMapping, function::{FuncArgs, KwArgs, OptionalArg}, protocol::PyIterReturn, slots::{self, Callable, PyTypeFlags, PyTypeSlots, SlotGetattro, SlotSetattro}, @@ -12,6 +13,7 @@ use crate::{ PyValue, TryFromObject, TypeProtocol, VirtualMachine, }; use itertools::Itertools; +use num_traits::ToPrimitive; use std::collections::HashSet; use std::fmt; use std::ops::Deref; @@ -270,6 +272,54 @@ impl PyType { }; update_slot!(iternext, func); } + "__len__" | "__getitem__" | "__setitem__" | "__delitem__" => { + macro_rules! then_some_closure { + ($cond:expr, $closure:expr) => { + if $cond { + Some($closure) + } else { + None + } + }; + } + + let func: slots::MappingFunc = |zelf, _vm| { + Ok(PyMapping { + length: then_some_closure!(zelf.has_class_attr("__len__"), |zelf, vm| { + vm.call_special_method(zelf, "__len__", ()).map(|obj| { + obj.payload_if_subclass::(vm) + .map(|length_obj| { + length_obj.as_bigint().to_usize().ok_or_else(|| { + vm.new_value_error( + "__len__() should return >= 0".to_owned(), + ) + }) + }) + .unwrap() + })? + }), + subscript: then_some_closure!( + zelf.has_class_attr("__getitem__"), + |zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine| { + vm.call_special_method(zelf, "__getitem__", (needle,)) + } + ), + ass_subscript: then_some_closure!( + zelf.has_class_attr("__setitem__") | zelf.has_class_attr("__delitem__"), + |zelf, needle, value, vm| match value { + Some(value) => vm + .call_special_method(zelf, "__setitem__", (needle, value),) + .map(|_| Ok(()))?, + None => vm + .call_special_method(zelf, "__delitem__", (needle,)) + .map(|_| Ok(()))?, + } + ), + }) + }; + update_slot!(as_mapping, func); + // TODO: need to update sequence protocol too + } _ => {} } } From 9e5120d546f2539c93082b04d18a54b5241859f7 Mon Sep 17 00:00:00 2001 From: snowapril Date: Wed, 29 Sep 2021 15:05:47 +0900 Subject: [PATCH 10/14] add mapping type check to mappingproxy As in cpython implementation there exists argument type checking before create mapping proxy like below. ```c if (!PyMapping_Check(mapping) || PyList_Check(mapping) || PyTuple_Check(mapping)) // print error ... ``` Signed-off-by: snowapril --- vm/src/builtins/dict.rs | 10 +++++++++- vm/src/builtins/mappingproxy.rs | 18 ++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index f4664b5d8a3..e9263b1999b 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -944,7 +944,15 @@ pub struct PyMapping { Option, &VirtualMachine) -> PyResult<()>>, } -impl PyMapping {} +impl PyMapping { + pub fn check(cls: &PyObjectRef, vm: &VirtualMachine) -> bool { + if let Ok(mapping) = PyMapping::try_from_borrowed_object(vm, cls) { + mapping.subscript.is_some() + } else { + false + } + } +} impl TryFromBorrowedObject for PyMapping { fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 6c63fecec42..bed79c4b186 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -1,4 +1,4 @@ -use super::{PyDict, PyStrRef, PyTypeRef}; +use super::{PyDict, PyList, PyStrRef, PyTuple, PyTypeRef}; use crate::{ builtins::dict::PyMapping, function::OptionalArg, @@ -37,10 +37,20 @@ impl SlotConstructor for PyMappingProxy { type Args = PyObjectRef; fn py_new(cls: PyTypeRef, mapping: Self::Args, vm: &VirtualMachine) -> PyResult { - Self { - mapping: MappingProxyInner::Dict(mapping), + if !PyMapping::check(&mapping, vm) + || mapping.payload_if_subclass::(vm).is_some() + || mapping.payload_if_subclass::(vm).is_some() + { + Err(vm.new_type_error(format!( + "mappingproxy() argument must be a mapping, not {}", + mapping.class() + ))) + } else { + Self { + mapping: MappingProxyInner::Dict(mapping), + } + .into_pyresult_with_type(vm, cls) } - .into_pyresult_with_type(vm, cls) } } From 4fd06814985efe66c76fb4579a22c7e716eb4f5f Mon Sep 17 00:00:00 2001 From: snowapril Date: Wed, 29 Sep 2021 15:38:39 +0900 Subject: [PATCH 11/14] move mapping protocol to rustpython_vm::protocol Signed-off-by: snowapril --- stdlib/src/array.rs | 6 +++--- vm/src/builtins/bytearray.rs | 3 +-- vm/src/builtins/bytes.rs | 3 +-- vm/src/builtins/dict.rs | 37 ++------------------------------- vm/src/builtins/list.rs | 3 +-- vm/src/builtins/mappingproxy.rs | 2 +- vm/src/builtins/memory.rs | 3 +-- vm/src/builtins/pytype.rs | 3 +-- vm/src/builtins/range.rs | 3 +-- vm/src/builtins/tuple.rs | 3 +-- vm/src/protocol/mapping.rs | 36 ++++++++++++++++++++++++++++++++ vm/src/protocol/mod.rs | 2 ++ vm/src/pyobject.rs | 2 +- vm/src/slots.rs | 4 ++-- 14 files changed, 54 insertions(+), 56 deletions(-) create mode 100644 vm/src/protocol/mapping.rs diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index 6984455aa8c..abf4065d954 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -12,12 +12,12 @@ mod array { }; use crate::vm::{ builtins::{ - dict::PyMapping, IntoPyFloat, PyByteArray, PyBytes, PyBytesRef, PyIntRef, PyList, - PyListRef, PySliceRef, PyStr, PyStrRef, PyTypeRef, + IntoPyFloat, PyByteArray, PyBytes, PyBytesRef, PyIntRef, PyList, PyListRef, PySliceRef, + PyStr, PyStrRef, PyTypeRef, }, class_or_notimplemented, function::{ArgBytesLike, ArgIterable, OptionalArg}, - protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard}, + protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMapping, ResizeGuard}, sliceable::{saturate_index, PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ AsBuffer, AsMapping, Comparable, Iterable, IteratorIterable, PyComparisonOp, diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 77139f93f90..26557401b43 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -9,14 +9,13 @@ use crate::common::{ }; use crate::{ anystr::{self, AnyStr}, - builtins::dict::PyMapping, bytesinner::{ bytes_decode, bytes_from_object, value_from_object, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner, }, function::{ArgBytesLike, ArgIterable, FuncArgs, OptionalArg, OptionalOption}, - protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, ResizeGuard}, + protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMapping, ResizeGuard}, sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable, diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 783763cc186..18ce64929e1 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -1,14 +1,13 @@ 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, }, common::hash::PyHash, function::{ArgBytesLike, ArgIterable, OptionalArg, OptionalOption}, - protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn}, + protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMapping}, slots::{ AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotConstructor, SlotIterator, diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index e9263b1999b..f856567be71 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -4,7 +4,7 @@ use crate::{ common::ascii, dictdatatype::{self, DictKey}, function::{ArgIterable, FuncArgs, KwArgs, OptionalArg}, - protocol::PyIterReturn, + protocol::{PyIterReturn, PyMapping}, slots::{ AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, Unhashable, @@ -13,7 +13,7 @@ use crate::{ IdProtocol, IntoPyObject, ItemProtocol, PyArithmeticValue::*, PyAttributes, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, - PyResult, PyValue, TryFromBorrowedObject, TypeProtocol, + PyResult, PyValue, TypeProtocol, }; use crossbeam_utils::atomic::AtomicCell; use std::fmt; @@ -935,36 +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); } - -#[allow(clippy::type_complexity)] -pub struct PyMapping { - pub length: Option PyResult>, - pub subscript: Option PyResult>, - pub ass_subscript: - Option, &VirtualMachine) -> PyResult<()>>, -} - -impl PyMapping { - pub fn check(cls: &PyObjectRef, vm: &VirtualMachine) -> bool { - if let Ok(mapping) = PyMapping::try_from_borrowed_object(vm, cls) { - mapping.subscript.is_some() - } else { - false - } - } -} - -impl TryFromBorrowedObject for PyMapping { - fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { - let obj_cls = obj.class(); - for cls in obj_cls.iter_mro() { - if let Some(f) = cls.slots.as_mapping.load() { - return f(obj, vm); - } - } - Err(vm.new_type_error(format!( - "a dict-like object is required, not '{}'", - obj_cls.name() - ))) - } -} diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index e80d10e2bbe..34dd2c2bf0f 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -7,9 +7,8 @@ use crate::common::lock::{ PyMappedRwLockReadGuard, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard, }; use crate::{ - builtins::dict::PyMapping, function::{ArgIterable, FuncArgs, OptionalArg}, - protocol::PyIterReturn, + protocol::{PyIterReturn, PyMapping}, sequence::{self, SimpleSeq}, sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index bed79c4b186..035e5b37649 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -1,7 +1,7 @@ use super::{PyDict, PyList, PyStrRef, PyTuple, PyTypeRef}; use crate::{ - builtins::dict::PyMapping, function::OptionalArg, + protocol::PyMapping, slots::{AsMapping, Iterable, SlotConstructor}, IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, VirtualMachine, diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index 4b682ddc256..fa8a2f98bbb 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -6,10 +6,9 @@ use crate::common::{ rc::PyRc, }; use crate::{ - builtins::dict::PyMapping, bytesinner::bytes_to_hex, function::{FuncArgs, OptionalArg}, - protocol::{BufferInternal, BufferOptions, PyBuffer}, + protocol::{BufferInternal, BufferOptions, PyBuffer, PyMapping}, sliceable::{convert_slice, wrap_index, SequenceIndex}, slots::{AsBuffer, AsMapping, Comparable, Hashable, PyComparisonOp, SlotConstructor}, stdlib::pystruct::FormatSpec, diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/pytype.rs index 4415c95dd3b..bd8757cef81 100644 --- a/vm/src/builtins/pytype.rs +++ b/vm/src/builtins/pytype.rs @@ -4,9 +4,8 @@ use super::{ }; use crate::common::{ascii, lock::PyRwLock}; use crate::{ - builtins::dict::PyMapping, function::{FuncArgs, KwArgs, OptionalArg}, - protocol::PyIterReturn, + protocol::{PyIterReturn, PyMapping}, slots::{self, Callable, PyTypeFlags, PyTypeSlots, SlotGetattro, SlotSetattro}, utils::Either, IdProtocol, PyAttributes, PyClassImpl, PyContext, PyLease, PyObjectRef, PyRef, PyResult, diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 66187c6fa25..792b29a2ac1 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -1,9 +1,8 @@ use super::{PyInt, PyIntRef, PySlice, PySliceRef, PyTypeRef}; use crate::common::hash::PyHash; use crate::{ - builtins::dict::PyMapping, function::{FuncArgs, OptionalArg}, - protocol::PyIterReturn, + protocol::{PyIterReturn, PyMapping}, slots::{ AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, }, diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 1dab3a0e9a0..6e7199e708e 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -3,11 +3,10 @@ use super::{ iter::IterStatus::{self, Active, Exhausted}, PyInt, PyTypeRef, }; -use crate::builtins::dict::PyMapping; use crate::common::hash::PyHash; use crate::{ function::OptionalArg, - protocol::PyIterReturn, + protocol::{PyIterReturn, PyMapping}, sequence::{self, SimpleSeq}, sliceable::PySliceableSequence, slots::{ diff --git a/vm/src/protocol/mapping.rs b/vm/src/protocol/mapping.rs new file mode 100644 index 00000000000..3003edcc490 --- /dev/null +++ b/vm/src/protocol/mapping.rs @@ -0,0 +1,36 @@ +//! Mapping protocol + +use crate::{vm::VirtualMachine, PyObjectRef, PyResult, TryFromBorrowedObject, TypeProtocol}; + +#[allow(clippy::type_complexity)] +pub struct PyMapping { + pub length: Option PyResult>, + pub subscript: Option PyResult>, + pub ass_subscript: + Option, &VirtualMachine) -> PyResult<()>>, +} + +impl PyMapping { + pub fn check(cls: &PyObjectRef, vm: &VirtualMachine) -> bool { + if let Ok(mapping) = PyMapping::try_from_borrowed_object(vm, cls) { + mapping.subscript.is_some() + } else { + false + } + } +} + +impl TryFromBorrowedObject for PyMapping { + fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { + let obj_cls = obj.class(); + for cls in obj_cls.iter_mro() { + if let Some(f) = cls.slots.as_mapping.load() { + return f(obj, vm); + } + } + Err(vm.new_type_error(format!( + "a dict-like object is required, not '{}'", + obj_cls.name() + ))) + } +} diff --git a/vm/src/protocol/mod.rs b/vm/src/protocol/mod.rs index 0c44ab75451..eb4ff328cb3 100644 --- a/vm/src/protocol/mod.rs +++ b/vm/src/protocol/mod.rs @@ -1,5 +1,7 @@ mod buffer; mod iter; +mod mapping; pub use buffer::{BufferInternal, BufferOptions, PyBuffer, ResizeGuard}; pub use iter::{PyIter, PyIterReturn}; +pub(crate) use mapping::PyMapping; diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index e268f320482..5306d28a702 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -10,7 +10,6 @@ use crate::{ builtinfunc::PyNativeFuncDef, bytearray, bytes, code::{self, PyCode}, - dict::PyMapping, getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetSet}, namespace::PyNamespace, object, pystr, @@ -21,6 +20,7 @@ use crate::{ dictdatatype::Dict, exceptions, function::{IntoFuncArgs, IntoPyNativeFunc}, + protocol::PyMapping, slots::{PyTypeFlags, PyTypeSlots}, types::{create_type_with_slots, TypeZoo}, VirtualMachine, diff --git a/vm/src/slots.rs b/vm/src/slots.rs index e5c5e7b2297..7252cc30f7e 100644 --- a/vm/src/slots.rs +++ b/vm/src/slots.rs @@ -1,8 +1,8 @@ -use crate::builtins::{dict::PyMapping, PyStrRef, PyTypeRef}; +use crate::builtins::{PyStrRef, PyTypeRef}; use crate::common::hash::PyHash; use crate::common::lock::PyRwLock; use crate::function::{FromArgs, FuncArgs, OptionalArg}; -use crate::protocol::{PyBuffer, PyIterReturn}; +use crate::protocol::{PyBuffer, PyIterReturn, PyMapping}; use crate::utils::Either; use crate::VirtualMachine; use crate::{ From aa2a7f01ee7c9ed4cac8731c788c3013653dc5aa Mon Sep 17 00:00:00 2001 From: snowapril Date: Thu, 30 Sep 2021 22:48:58 +0900 Subject: [PATCH 12/14] add PyMapping as PyObjectRef wrapper Modify original `PyMapping` to `PyMappingMethods` and create `PyMapping` struct as `PyObjectRef` wrapper for implementing `PyMapping_*` functions. https://docs.python.org/3/c-api/mapping.html Signed-off-by: snowapril --- stdlib/src/array.rs | 8 +- vm/src/builtins/bytearray.rs | 8 +- vm/src/builtins/bytes.rs | 6 +- vm/src/builtins/dict.rs | 8 +- vm/src/builtins/list.rs | 6 +- vm/src/builtins/mappingproxy.rs | 8 +- vm/src/builtins/memory.rs | 6 +- vm/src/builtins/pytype.rs | 4 +- vm/src/builtins/range.rs | 6 +- vm/src/builtins/tuple.rs | 6 +- vm/src/protocol/mapping.rs | 139 +++++++++++++++++++++++++++----- vm/src/protocol/mod.rs | 2 +- vm/src/pyobject.rs | 12 +-- vm/src/slots.rs | 8 +- 14 files changed, 165 insertions(+), 62 deletions(-) diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index abf4065d954..77273bda90b 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -17,7 +17,9 @@ mod array { }, class_or_notimplemented, function::{ArgBytesLike, ArgIterable, OptionalArg}, - protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMapping, ResizeGuard}, + protocol::{ + BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods, ResizeGuard, + }, sliceable::{saturate_index, PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ AsBuffer, AsMapping, Comparable, Iterable, IteratorIterable, PyComparisonOp, @@ -1165,8 +1167,8 @@ mod array { } impl AsMapping for PyArray { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: Some(Self::ass_subscript), diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 26557401b43..2d8e4c849f7 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -15,7 +15,9 @@ use crate::{ ByteInnerTranslateOptions, DecodeArgs, PyBytesInner, }, function::{ArgBytesLike, ArgIterable, FuncArgs, OptionalArg, OptionalOption}, - protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMapping, ResizeGuard}, + protocol::{ + BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods, ResizeGuard, + }, sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable, @@ -716,8 +718,8 @@ impl<'a> ResizeGuard<'a> for PyByteArray { } impl AsMapping for PyByteArray { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: Some(Self::ass_subscript), diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 18ce64929e1..f6ab7d478b9 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -7,7 +7,7 @@ use crate::{ }, common::hash::PyHash, function::{ArgBytesLike, ArgIterable, OptionalArg, OptionalOption}, - protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMapping}, + protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods}, slots::{ AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotConstructor, SlotIterator, @@ -541,8 +541,8 @@ impl BufferInternal for PyRef { } impl AsMapping for PyBytes { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: None, diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index f856567be71..122831d0b41 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -4,7 +4,7 @@ use crate::{ common::ascii, dictdatatype::{self, DictKey}, function::{ArgIterable, FuncArgs, KwArgs, OptionalArg}, - protocol::{PyIterReturn, PyMapping}, + protocol::{PyIterReturn, PyMappingMethods}, slots::{ AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, Unhashable, @@ -412,8 +412,8 @@ impl PyDict { } impl AsMapping for PyDict { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: Some(Self::ass_subscript), @@ -685,7 +685,7 @@ macro_rules! dict_iterator { } impl $name { - fn new(dict: PyDictRef) -> Self { + pub fn new(dict: PyDictRef) -> Self { $name { dict } } } diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index 34dd2c2bf0f..bee377e7aad 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -8,7 +8,7 @@ use crate::common::lock::{ }; use crate::{ function::{ArgIterable, FuncArgs, OptionalArg}, - protocol::{PyIterReturn, PyMapping}, + protocol::{PyIterReturn, PyMappingMethods}, sequence::{self, SimpleSeq}, sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex}, slots::{ @@ -418,8 +418,8 @@ impl PyList { } impl AsMapping for PyList { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: Some(Self::ass_subscript), diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 035e5b37649..a5fbaad98c0 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -1,7 +1,7 @@ use super::{PyDict, PyList, PyStrRef, PyTuple, PyTypeRef}; use crate::{ function::OptionalArg, - protocol::PyMapping, + protocol::{PyMapping, PyMappingMethods}, slots::{AsMapping, Iterable, SlotConstructor}, IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, VirtualMachine, @@ -37,7 +37,7 @@ impl SlotConstructor for PyMappingProxy { type Args = PyObjectRef; fn py_new(cls: PyTypeRef, mapping: Self::Args, vm: &VirtualMachine) -> PyResult { - if !PyMapping::check(&mapping, vm) + if !PyMapping::check(&mapping) || mapping.payload_if_subclass::(vm).is_some() || mapping.payload_if_subclass::(vm).is_some() { @@ -140,8 +140,8 @@ impl PyMappingProxy { } impl AsMapping for PyMappingProxy { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: None, subscript: Some(Self::subscript), ass_subscript: None, diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs index fa8a2f98bbb..1dd313dd44a 100644 --- a/vm/src/builtins/memory.rs +++ b/vm/src/builtins/memory.rs @@ -8,7 +8,7 @@ use crate::common::{ use crate::{ bytesinner::bytes_to_hex, function::{FuncArgs, OptionalArg}, - protocol::{BufferInternal, BufferOptions, PyBuffer, PyMapping}, + protocol::{BufferInternal, BufferOptions, PyBuffer, PyMappingMethods}, sliceable::{convert_slice, wrap_index, SequenceIndex}, slots::{AsBuffer, AsMapping, Comparable, Hashable, PyComparisonOp, SlotConstructor}, stdlib::pystruct::FormatSpec, @@ -735,8 +735,8 @@ impl BufferInternal for PyRef { } impl AsMapping for PyMemoryView { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: Some(Self::ass_subscript), diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/pytype.rs index bd8757cef81..9db1530c8af 100644 --- a/vm/src/builtins/pytype.rs +++ b/vm/src/builtins/pytype.rs @@ -5,7 +5,7 @@ use super::{ use crate::common::{ascii, lock::PyRwLock}; use crate::{ function::{FuncArgs, KwArgs, OptionalArg}, - protocol::{PyIterReturn, PyMapping}, + protocol::{PyIterReturn, PyMappingMethods}, slots::{self, Callable, PyTypeFlags, PyTypeSlots, SlotGetattro, SlotSetattro}, utils::Either, IdProtocol, PyAttributes, PyClassImpl, PyContext, PyLease, PyObjectRef, PyRef, PyResult, @@ -283,7 +283,7 @@ impl PyType { } let func: slots::MappingFunc = |zelf, _vm| { - Ok(PyMapping { + Ok(PyMappingMethods { length: then_some_closure!(zelf.has_class_attr("__len__"), |zelf, vm| { vm.call_special_method(zelf, "__len__", ()).map(|obj| { obj.payload_if_subclass::(vm) diff --git a/vm/src/builtins/range.rs b/vm/src/builtins/range.rs index 792b29a2ac1..6c9d0a0dbb6 100644 --- a/vm/src/builtins/range.rs +++ b/vm/src/builtins/range.rs @@ -2,7 +2,7 @@ use super::{PyInt, PyIntRef, PySlice, PySliceRef, PyTypeRef}; use crate::common::hash::PyHash; use crate::{ function::{FuncArgs, OptionalArg}, - protocol::{PyIterReturn, PyMapping}, + protocol::{PyIterReturn, PyMappingMethods}, slots::{ AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator, }, @@ -375,8 +375,8 @@ impl PyRange { } impl AsMapping for PyRange { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: None, diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 6e7199e708e..3f5e8e51dff 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -6,7 +6,7 @@ use super::{ use crate::common::hash::PyHash; use crate::{ function::OptionalArg, - protocol::{PyIterReturn, PyMapping}, + protocol::{PyIterReturn, PyMappingMethods}, sequence::{self, SimpleSeq}, sliceable::PySliceableSequence, slots::{ @@ -288,8 +288,8 @@ impl PyTuple { } impl AsMapping for PyTuple { - fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { - Ok(PyMapping { + fn as_mapping(_zelf: &PyRef, _vm: &VirtualMachine) -> PyResult { + Ok(PyMappingMethods { length: Some(Self::length), subscript: Some(Self::subscript), ass_subscript: None, diff --git a/vm/src/protocol/mapping.rs b/vm/src/protocol/mapping.rs index 3003edcc490..bf832cf1f78 100644 --- a/vm/src/protocol/mapping.rs +++ b/vm/src/protocol/mapping.rs @@ -1,36 +1,135 @@ -//! Mapping protocol - -use crate::{vm::VirtualMachine, PyObjectRef, PyResult, TryFromBorrowedObject, TypeProtocol}; +use crate::{ + builtins::dict::{PyDictKeys, PyDictRef, PyDictValues}, + builtins::list::PyList, + vm::VirtualMachine, + IdProtocol, IntoPyObject, PyObjectRef, PyResult, TryFromObject, TypeProtocol, +}; +use std::borrow::Borrow; +use std::ops::Deref; +// Mapping protocol +// https://docs.python.org/3/c-api/mapping.html #[allow(clippy::type_complexity)] -pub struct PyMapping { +#[derive(Default)] +pub struct PyMappingMethods { pub length: Option PyResult>, pub subscript: Option PyResult>, pub ass_subscript: Option, &VirtualMachine) -> PyResult<()>>, } -impl PyMapping { - pub fn check(cls: &PyObjectRef, vm: &VirtualMachine) -> bool { - if let Ok(mapping) = PyMapping::try_from_borrowed_object(vm, cls) { - mapping.subscript.is_some() - } else { - false - } +#[derive(Debug, Clone)] +#[repr(transparent)] +pub struct PyMapping(T) +where + T: Borrow; + +impl PyMapping { + pub fn into_object(self) -> PyObjectRef { + self.0 } -} -impl TryFromBorrowedObject for PyMapping { - fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { - let obj_cls = obj.class(); + pub fn check(obj: &PyObjectRef) -> bool { + obj.class() + .mro_find_map(|x| x.slots.as_mapping.load()) + .is_some() + } + + pub fn methods(&self, vm: &VirtualMachine) -> PyMappingMethods { + let obj_cls = self.0.class(); for cls in obj_cls.iter_mro() { if let Some(f) = cls.slots.as_mapping.load() { - return f(obj, vm); + return f(&self.0, vm).unwrap(); } } - Err(vm.new_type_error(format!( - "a dict-like object is required, not '{}'", - obj_cls.name() - ))) + PyMappingMethods::default() + } +} + +impl PyMapping +where + T: Borrow, +{ + pub fn new(obj: T) -> Self { + Self(obj) + } + + pub fn keys(&self, vm: &VirtualMachine) -> PyResult { + if self.0.borrow().is(&vm.ctx.types.dict_type) { + Ok( + PyDictKeys::new(PyDictRef::try_from_object(vm, self.0.borrow().clone())?) + .into_pyobject(vm), + ) + } else { + Self::method_output_as_list(self.0.borrow(), "keys", vm) + } + } + + pub fn values(&self, vm: &VirtualMachine) -> PyResult { + if self.0.borrow().is(&vm.ctx.types.dict_type) { + Ok( + PyDictValues::new(PyDictRef::try_from_object(vm, self.0.borrow().clone())?) + .into_pyobject(vm), + ) + } else { + Self::method_output_as_list(self.0.borrow(), "values", vm) + } + } + + fn method_output_as_list( + obj: &PyObjectRef, + method_name: &str, + vm: &VirtualMachine, + ) -> PyResult { + let meth_output = vm.call_method(obj, method_name, ())?; + if meth_output.is(&vm.ctx.types.list_type) { + return Ok(meth_output); + } + + let iter = meth_output.clone().get_iter(vm).map_err(|_| { + vm.new_type_error(format!( + "{}.{}() returned a non-iterable (type {})", + obj.class(), + method_name, + meth_output.class() + )) + })?; + + Ok(PyList::from(vm.extract_elements(&iter)?).into_pyobject(vm)) + } +} + +impl Borrow for PyMapping +where + T: Borrow, +{ + fn borrow(&self) -> &PyObjectRef { + self.0.borrow() + } +} + +impl Deref for PyMapping +where + T: Borrow, +{ + type Target = PyObjectRef; + fn deref(&self) -> &Self::Target { + self.0.borrow() + } +} + +impl IntoPyObject for PyMapping { + fn into_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef { + self.into_object() + } +} + +impl TryFromObject for PyMapping { + fn try_from_object(vm: &VirtualMachine, mapping: PyObjectRef) -> PyResult { + if Self::check(&mapping) { + Ok(Self::new(mapping)) + } else { + Err(vm.new_type_error(format!("{} is not a mapping object", mapping.class()))) + } } } diff --git a/vm/src/protocol/mod.rs b/vm/src/protocol/mod.rs index eb4ff328cb3..548eaaee122 100644 --- a/vm/src/protocol/mod.rs +++ b/vm/src/protocol/mod.rs @@ -4,4 +4,4 @@ mod mapping; pub use buffer::{BufferInternal, BufferOptions, PyBuffer, ResizeGuard}; pub use iter::{PyIter, PyIterReturn}; -pub(crate) use mapping::PyMapping; +pub use mapping::{PyMapping, PyMappingMethods}; diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 5306d28a702..b51e5a000d2 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -640,8 +640,8 @@ where T: IntoPyObject, { fn get_item(&self, key: T, vm: &VirtualMachine) -> PyResult { - if let Ok(map) = PyMapping::try_from_borrowed_object(vm, self) { - if let Some(getitem) = map.subscript { + if let Ok(mapping) = PyMapping::try_from_object(vm, self.clone()) { + if let Some(getitem) = mapping.methods(vm).subscript { return getitem(self.clone(), key.into_pyobject(vm), vm); } } @@ -663,8 +663,8 @@ where } fn set_item(&self, key: T, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - if let Ok(map) = PyMapping::try_from_borrowed_object(vm, self) { - if let Some(setitem) = map.ass_subscript { + if let Ok(mapping) = PyMapping::try_from_object(vm, self.clone()) { + if let Some(setitem) = mapping.methods(vm).ass_subscript { return setitem(self.clone(), key.into_pyobject(vm), Some(value), vm); } } @@ -681,8 +681,8 @@ where } fn del_item(&self, key: T, vm: &VirtualMachine) -> PyResult<()> { - if let Ok(map) = PyMapping::try_from_borrowed_object(vm, self) { - if let Some(setitem) = map.ass_subscript { + if let Ok(mapping) = PyMapping::try_from_object(vm, self.clone()) { + if let Some(setitem) = mapping.methods(vm).ass_subscript { return setitem(self.clone(), key.into_pyobject(vm), None, vm); } } diff --git a/vm/src/slots.rs b/vm/src/slots.rs index 7252cc30f7e..99c25264e37 100644 --- a/vm/src/slots.rs +++ b/vm/src/slots.rs @@ -2,7 +2,7 @@ use crate::builtins::{PyStrRef, PyTypeRef}; use crate::common::hash::PyHash; use crate::common::lock::PyRwLock; use crate::function::{FromArgs, FuncArgs, OptionalArg}; -use crate::protocol::{PyBuffer, PyIterReturn, PyMapping}; +use crate::protocol::{PyBuffer, PyIterReturn, PyMappingMethods}; use crate::utils::Either; use crate::VirtualMachine; use crate::{ @@ -70,7 +70,7 @@ pub(crate) type GetattroFunc = fn(PyObjectRef, PyStrRef, &VirtualMachine) -> PyR pub(crate) type SetattroFunc = fn(&PyObjectRef, PyStrRef, Option, &VirtualMachine) -> PyResult<()>; pub(crate) type BufferFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult; -pub(crate) type MappingFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult; +pub(crate) type MappingFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult; pub(crate) type IterFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult; pub(crate) type IterNextFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult; @@ -536,7 +536,7 @@ pub trait AsBuffer: PyValue { #[pyimpl] pub trait AsMapping: PyValue { #[pyslot] - fn slot_as_mapping(zelf: &PyObjectRef, vm: &VirtualMachine) -> PyResult { + fn slot_as_mapping(zelf: &PyObjectRef, vm: &VirtualMachine) -> PyResult { let zelf = zelf .downcast_ref() .ok_or_else(|| vm.new_type_error("unexpected payload for as_mapping".to_owned()))?; @@ -563,7 +563,7 @@ pub trait AsMapping: PyValue { }) } - fn as_mapping(zelf: &PyRef, vm: &VirtualMachine) -> PyResult; + fn as_mapping(zelf: &PyRef, vm: &VirtualMachine) -> PyResult; fn length(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult; From a81b3f91b92682b2add5a4c1af0ead4b50ac7dcb Mon Sep 17 00:00:00 2001 From: snowapril Date: Sat, 2 Oct 2021 14:35:45 +0900 Subject: [PATCH 13/14] fix posix & winapi to use proper PyMapping Signed-off-by: snowapril --- vm/src/stdlib/posix.rs | 24 ++++++++++++++++++++---- vm/src/stdlib/winapi.rs | 33 ++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/vm/src/stdlib/posix.rs b/vm/src/stdlib/posix.rs index 58f10618e10..ae6251a5a77 100644 --- a/vm/src/stdlib/posix.rs +++ b/vm/src/stdlib/posix.rs @@ -1049,8 +1049,24 @@ pub mod module { } #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))] - fn envp_from_dict(dict: PyDictRef, vm: &VirtualMachine) -> PyResult> { - dict.into_iter() + fn envp_from_dict( + env: crate::protocol::PyMapping, + vm: &VirtualMachine, + ) -> PyResult> { + let keys = env.keys(vm)?; + let values = env.values(vm)?; + + let keys = PyListRef::try_from_object(vm, keys) + .map_err(|_| vm.new_type_error("env.keys() is not a list".to_owned()))? + .borrow_vec() + .to_vec(); + let values = PyListRef::try_from_object(vm, values) + .map_err(|_| vm.new_type_error("env.values() is not a list".to_owned()))? + .borrow_vec() + .to_vec(); + + keys.into_iter() + .zip(values.into_iter()) .map(|(k, v)| { let k = PyPathLike::try_from_object(vm, k)?.into_bytes(); let v = PyPathLike::try_from_object(vm, v)?.into_bytes(); @@ -1085,7 +1101,7 @@ pub mod module { #[pyarg(positional)] args: crate::function::ArgIterable, #[pyarg(positional)] - env: crate::builtins::dict::PyMapping, + env: crate::protocol::PyMapping, #[pyarg(named, default)] file_actions: Option>, #[pyarg(named, default)] @@ -1198,7 +1214,7 @@ pub mod module { .map(|s| s.as_ptr() as _) .chain(std::iter::once(std::ptr::null_mut())) .collect(); - let mut env = envp_from_dict(self.env.into_dict(), vm)?; + let mut env = envp_from_dict(self.env, vm)?; let envp: Vec<*mut libc::c_char> = env .iter_mut() .map(|s| s.as_ptr() as _) diff --git a/vm/src/stdlib/winapi.rs b/vm/src/stdlib/winapi.rs index 5ca3e207125..1ce91a83781 100644 --- a/vm/src/stdlib/winapi.rs +++ b/vm/src/stdlib/winapi.rs @@ -2,10 +2,11 @@ use super::os::errno_err; use crate::{ - builtins::{dict::PyMapping, PyDictRef, PyStrRef}, + builtins::{PyListRef, PyStrRef}, exceptions::IntoPyException, function::OptionalArg, - PyObjectRef, PyResult, PySequence, TryFromObject, VirtualMachine, + protocol::PyMapping, + ItemProtocol, PyObjectRef, PyResult, PySequence, TryFromObject, VirtualMachine, }; use std::ptr::{null, null_mut}; use winapi::shared::winerror; @@ -155,7 +156,7 @@ fn _winapi_CreateProcess( let mut env = args .env_mapping - .map(|m| getenvironment(m.into_dict(), vm)) + .map(|m| getenvironment(m, vm)) .transpose()?; let env = env.as_mut().map_or_else(null_mut, |v| v.as_mut_ptr()); @@ -216,9 +217,21 @@ fn _winapi_CreateProcess( )) } -fn getenvironment(env: PyDictRef, vm: &VirtualMachine) -> PyResult> { +fn getenvironment(env: PyMapping, vm: &VirtualMachine) -> PyResult> { + let keys = env.keys(vm)?; + let values = env.values(vm)?; + + let keys = PyListRef::try_from_object(vm, keys)?.borrow_vec().to_vec(); + let values = PyListRef::try_from_object(vm, values)? + .borrow_vec() + .to_vec(); + + if keys.len() != values.len() { + return Err(vm.new_runtime_error("environment changed size during iteration".to_owned())); + } + let mut out = widestring::WideString::new(); - for (k, v) in env { + for (k, v) in keys.into_iter().zip(values.into_iter()) { let k = PyStrRef::try_from_object(vm, k)?; let k = k.as_str(); let v = PyStrRef::try_from_object(vm, v)?; @@ -252,10 +265,11 @@ impl Drop for AttrList { fn getattributelist(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult> { >::try_from_object(vm, obj)? - .map(|d| { - let d = d.into_dict(); - let handlelist = d - .get_item_option("handle_list", vm)? + .map(|mapping| { + let handlelist = mapping + .into_object() + .get_item("handle_list", vm) + .ok() .and_then(|obj| { >>::try_from_object(vm, obj) .map(|s| match s { @@ -265,6 +279,7 @@ fn getattributelist(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult Date: Sat, 2 Oct 2021 18:00:04 +0900 Subject: [PATCH 14/14] turn unreachable function to cold --- vm/src/builtins/bytes.rs | 2 +- vm/src/builtins/mappingproxy.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index f6ab7d478b9..f24d5e345eb 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -559,7 +559,7 @@ impl AsMapping for PyBytes { Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))? } - #[inline] + #[cold] fn ass_subscript( zelf: PyObjectRef, _needle: PyObjectRef, diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index a5fbaad98c0..225fd143262 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -158,7 +158,7 @@ impl AsMapping for PyMappingProxy { Self::downcast_ref(&zelf, vm).map(|zelf| zelf.getitem(needle, vm))? } - #[inline] + #[cold] fn ass_subscript( zelf: PyObjectRef, _needle: PyObjectRef,