Skip to content

Commit 6d0abe6

Browse files
committed
mapping proxy holds PyMapping
1 parent 83a146d commit 6d0abe6

File tree

3 files changed

+57
-58
lines changed

3 files changed

+57
-58
lines changed

vm/src/builtins/mappingproxy.rs

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{PyDict, PyGenericAlias, PyList, PyTuple, PyType, PyTypeRef};
22
use crate::{
33
class::PyClassImpl,
44
convert::ToPyObject,
5-
function::OptionalArg,
5+
function::{ArgMapping, OptionalArg},
66
protocol::{PyMapping, PyMappingMethods, PySequence, PySequenceMethods},
77
types::{AsMapping, AsSequence, Constructor, Iterable},
88
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
@@ -18,7 +18,7 @@ pub struct PyMappingProxy {
1818
#[derive(Debug)]
1919
enum MappingProxyInner {
2020
Class(PyTypeRef),
21-
Dict(PyObjectRef),
21+
Mapping(ArgMapping),
2222
}
2323

2424
impl PyPayload for PyMappingProxy {
@@ -39,21 +39,21 @@ impl Constructor for PyMappingProxy {
3939
type Args = PyObjectRef;
4040

4141
fn py_new(cls: PyTypeRef, mapping: Self::Args, vm: &VirtualMachine) -> PyResult {
42-
if !PyMapping::check(mapping.as_ref(), vm)
43-
|| mapping.payload_if_subclass::<PyList>(vm).is_some()
44-
|| mapping.payload_if_subclass::<PyTuple>(vm).is_some()
45-
{
46-
Err(vm.new_type_error(format!(
47-
"mappingproxy() argument must be a mapping, not {}",
48-
mapping.class()
49-
)))
50-
} else {
51-
Self {
52-
mapping: MappingProxyInner::Dict(mapping),
42+
if let Some(methods) = PyMapping::find_methods(&mapping, vm) {
43+
if mapping.payload_if_subclass::<PyList>(vm).is_none()
44+
&& mapping.payload_if_subclass::<PyTuple>(vm).is_none()
45+
{
46+
return Self {
47+
mapping: MappingProxyInner::Mapping(ArgMapping::with_methods(mapping, methods)),
48+
}
49+
.into_ref_with_type(vm, cls)
50+
.map(Into::into);
5351
}
54-
.into_ref_with_type(vm, cls)
55-
.map(Into::into)
5652
}
53+
Err(vm.new_type_error(format!(
54+
"mappingproxy() argument must be a mapping, not {}",
55+
mapping.class()
56+
)))
5757
}
5858
}
5959

@@ -64,7 +64,7 @@ impl PyMappingProxy {
6464
MappingProxyInner::Class(class) => key
6565
.as_interned_str(vm)
6666
.and_then(|key| class.attributes.read().get(key).cloned()),
67-
MappingProxyInner::Dict(obj) => obj.get_item(&*key, vm).ok(),
67+
MappingProxyInner::Mapping(mapping) => mapping.mapping().subscript(&*key, vm).ok(),
6868
};
6969
Ok(opt)
7070
}
@@ -92,7 +92,7 @@ impl PyMappingProxy {
9292
MappingProxyInner::Class(class) => Ok(key
9393
.as_interned_str(vm)
9494
.map_or(false, |key| class.attributes.read().contains_key(key))),
95-
MappingProxyInner::Dict(obj) => PySequence::from(obj.as_ref()).contains(key, vm),
95+
MappingProxyInner::Mapping(obj) => PySequence::from(obj.as_ref()).contains(key, vm),
9696
}
9797
}
9898

@@ -101,53 +101,42 @@ impl PyMappingProxy {
101101
self._contains(&key, vm)
102102
}
103103

104-
#[pymethod]
105-
pub fn items(&self, vm: &VirtualMachine) -> PyResult {
106-
let obj = match &self.mapping {
107-
MappingProxyInner::Dict(d) => d.clone(),
104+
fn to_object(&self, vm: &VirtualMachine) -> PyResult {
105+
Ok(match &self.mapping {
106+
MappingProxyInner::Mapping(d) => d.as_ref().to_owned(),
108107
MappingProxyInner::Class(c) => {
109108
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
110109
}
111-
};
110+
})
111+
}
112+
113+
#[pymethod]
114+
pub fn items(&self, vm: &VirtualMachine) -> PyResult {
115+
let obj = self.to_object(vm)?;
112116
vm.call_method(&obj, identifier!(vm, items).as_str(), ())
113117
}
114118
#[pymethod]
115119
pub fn keys(&self, vm: &VirtualMachine) -> PyResult {
116-
let obj = match &self.mapping {
117-
MappingProxyInner::Dict(d) => d.clone(),
118-
MappingProxyInner::Class(c) => {
119-
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
120-
}
121-
};
120+
let obj = self.to_object(vm)?;
122121
vm.call_method(&obj, identifier!(vm, keys).as_str(), ())
123122
}
124123
#[pymethod]
125124
pub fn values(&self, vm: &VirtualMachine) -> PyResult {
126-
let obj = match &self.mapping {
127-
MappingProxyInner::Dict(d) => d.clone(),
128-
MappingProxyInner::Class(c) => {
129-
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
130-
}
131-
};
125+
let obj = self.to_object(vm)?;
132126
vm.call_method(&obj, identifier!(vm, values).as_str(), ())
133127
}
134128
#[pymethod]
135129
pub fn copy(&self, vm: &VirtualMachine) -> PyResult {
136130
match &self.mapping {
137-
MappingProxyInner::Dict(d) => vm.call_method(d, identifier!(vm, copy).as_str(), ()),
131+
MappingProxyInner::Mapping(d) => vm.call_method(d, identifier!(vm, copy).as_str(), ()),
138132
MappingProxyInner::Class(c) => {
139133
Ok(PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm))
140134
}
141135
}
142136
}
143137
#[pymethod(magic)]
144138
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
145-
let obj = match &self.mapping {
146-
MappingProxyInner::Dict(d) => d.clone(),
147-
MappingProxyInner::Class(c) => {
148-
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
149-
}
150-
};
139+
let obj = self.to_object(vm)?;
151140
Ok(format!("mappingproxy({})", obj.repr(vm)?))
152141
}
153142

@@ -185,13 +174,7 @@ impl PyMappingProxy {
185174

186175
impl Iterable for PyMappingProxy {
187176
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
188-
let obj = match &zelf.mapping {
189-
MappingProxyInner::Dict(d) => d.clone(),
190-
MappingProxyInner::Class(c) => {
191-
// TODO: something that's much more efficient than this
192-
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
193-
}
194-
};
177+
let obj = zelf.to_object(vm)?;
195178
let iter = obj.get_iter(vm)?;
196179
Ok(iter.into())
197180
}

vm/src/function/protocol.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
types::AsMapping,
88
AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
99
};
10-
use std::{borrow::Borrow, marker::PhantomData};
10+
use std::{borrow::Borrow, marker::PhantomData, ops::Deref};
1111

1212
#[derive(Clone, Debug)]
1313
pub struct ArgCallable {
@@ -100,24 +100,29 @@ where
100100
}
101101
}
102102

103-
#[derive(Clone)]
103+
#[derive(Debug, Clone)]
104104
pub struct ArgMapping {
105105
obj: PyObjectRef,
106-
mapping_methods: &'static PyMappingMethods,
106+
methods: &'static PyMappingMethods,
107107
}
108108

109109
impl ArgMapping {
110+
#[inline]
111+
pub fn with_methods(obj: PyObjectRef, methods: &'static PyMappingMethods) -> Self {
112+
Self { obj, methods }
113+
}
114+
110115
#[inline(always)]
111116
pub fn from_dict_exact(dict: PyDictRef) -> Self {
112117
Self {
113118
obj: dict.into(),
114-
mapping_methods: &PyDict::AS_MAPPING,
119+
methods: &PyDict::AS_MAPPING,
115120
}
116121
}
117122

118123
#[inline(always)]
119124
pub fn mapping(&self) -> PyMapping {
120-
PyMapping::with_methods(&self.obj, self.mapping_methods)
125+
PyMapping::with_methods(&self.obj, self.methods)
121126
}
122127
}
123128

@@ -135,6 +140,14 @@ impl AsRef<PyObject> for ArgMapping {
135140
}
136141
}
137142

143+
impl Deref for ArgMapping {
144+
type Target = PyObject;
145+
#[inline(always)]
146+
fn deref(&self) -> &PyObject {
147+
&self.obj
148+
}
149+
}
150+
138151
impl From<ArgMapping> for PyObjectRef {
139152
#[inline(always)]
140153
fn from(value: ArgMapping) -> PyObjectRef {
@@ -152,11 +165,8 @@ impl ToPyObject for ArgMapping {
152165
impl TryFromObject for ArgMapping {
153166
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
154167
let mapping = PyMapping::try_protocol(&obj, vm)?;
155-
let mapping_methods = mapping.methods;
156-
Ok(Self {
157-
obj,
158-
mapping_methods,
159-
})
168+
let methods = mapping.methods;
169+
Ok(Self { obj, methods })
160170
}
161171
}
162172

vm/src/protocol/mapping.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ pub struct PyMappingMethods {
1717
Option<fn(&PyMapping, &PyObject, Option<PyObjectRef>, &VirtualMachine) -> PyResult<()>>,
1818
}
1919

20+
impl std::fmt::Debug for PyMappingMethods {
21+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
22+
write!(f, "mapping methods")
23+
}
24+
}
25+
2026
impl PyMappingMethods {
2127
fn check(&self) -> bool {
2228
self.subscript.is_some()

0 commit comments

Comments
 (0)