Skip to content

Commit 0ec034d

Browse files
committed
Change property.__new__ to use new style function and construct
PyProperty
1 parent 2edfe4c commit 0ec034d

File tree

7 files changed

+69
-56
lines changed

7 files changed

+69
-56
lines changed

vm/src/function.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::marker::PhantomData;
33
use std::ops::Deref;
44

55
use crate::obj::objtype;
6+
use crate::obj::objtype::PyClassRef;
67
use crate::pyobject::{
78
IntoPyObject, PyContext, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
89
TryFromObject, TypeProtocol,
@@ -44,6 +45,25 @@ where
4445
_payload: PhantomData,
4546
}
4647
}
48+
49+
pub fn new_with_type(vm: &mut VirtualMachine, payload: T, cls: PyClassRef) -> PyResult<Self> {
50+
let required_type = T::required_type(&vm.ctx);
51+
if objtype::issubclass(&cls.obj, &required_type) {
52+
Ok(PyRef {
53+
obj: PyObject::new(
54+
PyObjectPayload::AnyRustValue {
55+
value: Box::new(payload),
56+
},
57+
cls.obj,
58+
),
59+
_payload: PhantomData,
60+
})
61+
} else {
62+
let subtype = vm.to_pystr(&cls.obj)?;
63+
let basetype = vm.to_pystr(&required_type)?;
64+
Err(vm.new_type_error(format!("{} is not a subtype of {}", subtype, basetype)))
65+
}
66+
}
4767
}
4868

4969
impl<T> Deref for PyRef<T>

vm/src/obj/objcode.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,7 @@ fn code_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7979
}
8080

8181
fn member_code_obj(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult<bytecode::CodeObject> {
82-
arg_check!(
83-
vm,
84-
args,
85-
required = [
86-
(zelf, Some(vm.ctx.code_type()))
87-
]
88-
);
82+
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.code_type()))]);
8983
Ok(get_value(zelf))
9084
}
9185

vm/src/obj/objfunction.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub fn init(context: &PyContext) {
2020
context.new_rustfunc(bind_method),
2121
);
2222

23-
2423
let classmethod_type = &context.classmethod_type;
2524
context.set_attr(
2625
&classmethod_type,

vm/src/obj/objobject.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use super::objstr;
22
use super::objtype;
33
use crate::function::PyRef;
4+
use crate::obj::objproperty::PropertyBuilder;
45
use crate::pyobject::{
56
AttributeProtocol, DictProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject,
67
PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
78
};
89
use crate::vm::VirtualMachine;
910
use std::cell::RefCell;
1011
use std::collections::HashMap;
11-
use crate::obj::objproperty::PropertyBuilder;
1212

1313
#[derive(Clone, Debug)]
1414
pub struct PyInstance;
@@ -174,7 +174,8 @@ pub fn init(context: &PyContext) {
174174
"__class__",
175175
PropertyBuilder::new(context)
176176
.add_getter(object_class)
177-
.add_setter(object_class_setter).create(),
177+
.add_setter(object_class_setter)
178+
.create(),
178179
);
179180
context.set_attr(&object, "__eq__", context.new_rustfunc(object_eq));
180181
context.set_attr(&object, "__ne__", context.new_rustfunc(object_ne));
@@ -183,11 +184,7 @@ pub fn init(context: &PyContext) {
183184
context.set_attr(&object, "__gt__", context.new_rustfunc(object_gt));
184185
context.set_attr(&object, "__ge__", context.new_rustfunc(object_ge));
185186
context.set_attr(&object, "__delattr__", context.new_rustfunc(object_delattr));
186-
context.set_attr(
187-
&object,
188-
"__dict__",
189-
context.new_property(object_dict),
190-
);
187+
context.set_attr(&object, "__dict__", context.new_property(object_dict));
191188
context.set_attr(&object, "__dir__", context.new_rustfunc(object_dir));
192189
context.set_attr(&object, "__hash__", context.new_rustfunc(object_hash));
193190
context.set_attr(&object, "__str__", context.new_rustfunc(object_str));

vm/src/obj/objproperty.rs

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22
33
*/
44

5-
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectRef, PyObjectPayload, PyObjectPayload2, PyResult, TypeProtocol};
5+
use crate::function::PyRef;
6+
use crate::obj::objstr::PyStringRef;
7+
use crate::obj::objtype::PyClassRef;
68
use crate::pyobject::IntoPyNativeFunc;
9+
use crate::pyobject::{
10+
OptionalArg, PyContext, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
11+
};
712
use crate::VirtualMachine;
8-
use crate::function::PyRef;
913
use std::marker::PhantomData;
10-
use crate::obj::objtype::PyClassRef;
1114

1215
/// Read-only property, doesn't have __set__ or __delete__
1316
#[derive(Debug)]
1417
pub struct PyReadOnlyProperty {
15-
getter: PyObjectRef
18+
getter: PyObjectRef,
1619
}
1720

1821
impl PyObjectPayload2 for PyReadOnlyProperty {
@@ -34,7 +37,7 @@ impl PyReadOnlyPropertyRef {
3437
pub struct PyProperty {
3538
getter: Option<PyObjectRef>,
3639
setter: Option<PyObjectRef>,
37-
deleter: Option<PyObjectRef>
40+
deleter: Option<PyObjectRef>,
3841
}
3942

4043
impl PyObjectPayload2 for PyProperty {
@@ -46,6 +49,25 @@ impl PyObjectPayload2 for PyProperty {
4649
pub type PyPropertyRef = PyRef<PyProperty>;
4750

4851
impl PyPropertyRef {
52+
fn new_property(
53+
cls: PyClassRef,
54+
fget: OptionalArg<PyObjectRef>,
55+
fset: OptionalArg<PyObjectRef>,
56+
fdel: OptionalArg<PyObjectRef>,
57+
_doc: OptionalArg<PyStringRef>,
58+
vm: &mut VirtualMachine,
59+
) -> PyResult<PyPropertyRef> {
60+
Self::new_with_type(
61+
vm,
62+
PyProperty {
63+
getter: fget.into_option(),
64+
setter: fset.into_option(),
65+
deleter: fdel.into_option(),
66+
},
67+
cls,
68+
)
69+
}
70+
4971
fn get(self, obj: PyObjectRef, _owner: PyClassRef, vm: &mut VirtualMachine) -> PyResult {
5072
if let Some(getter) = self.getter.as_ref() {
5173
vm.invoke(getter.clone(), obj)
@@ -75,37 +97,36 @@ pub struct PropertyBuilder<'a, T> {
7597
ctx: &'a PyContext,
7698
getter: Option<PyObjectRef>,
7799
setter: Option<PyObjectRef>,
78-
_return: PhantomData<T>
100+
_return: PhantomData<T>,
79101
}
80102

81-
82103
impl<'a, T> PropertyBuilder<'a, T> {
83104
pub fn new(ctx: &'a PyContext) -> Self {
84105
Self {
85106
ctx,
86107
getter: None,
87108
setter: None,
88-
_return: PhantomData
109+
_return: PhantomData,
89110
}
90111
}
91112

92-
pub fn add_getter<I, F:IntoPyNativeFunc<I, T>>(self, func: F) -> Self {
113+
pub fn add_getter<I, F: IntoPyNativeFunc<I, T>>(self, func: F) -> Self {
93114
let func = self.ctx.new_rustfunc(func);
94115
Self {
95116
ctx: self.ctx,
96117
getter: Some(func),
97118
setter: self.setter,
98-
_return: PhantomData
119+
_return: PhantomData,
99120
}
100121
}
101122

102-
pub fn add_setter<I, F:IntoPyNativeFunc<(I, T), PyResult>>(self, func: F) -> Self {
123+
pub fn add_setter<I, F: IntoPyNativeFunc<(I, T), PyResult>>(self, func: F) -> Self {
103124
let func = self.ctx.new_rustfunc(func);
104125
Self {
105126
ctx: self.ctx,
106127
getter: self.getter,
107128
setter: Some(func),
108-
_return: PhantomData
129+
_return: PhantomData,
109130
}
110131
}
111132

@@ -114,31 +135,32 @@ impl<'a, T> PropertyBuilder<'a, T> {
114135
let payload = PyProperty {
115136
getter: self.getter.clone(),
116137
setter: self.setter.clone(),
117-
deleter: None
138+
deleter: None,
118139
};
119140

120141
PyObject::new(
121142
PyObjectPayload::AnyRustValue {
122-
value: Box::new(payload)
143+
value: Box::new(payload),
123144
},
124145
self.ctx.property_type(),
125146
)
126147
} else {
127148
let payload = PyReadOnlyProperty {
128-
getter: self.getter.expect("One of add_getter/add_setter must be called when constructing a property")
149+
getter: self.getter.expect(
150+
"One of add_getter/add_setter must be called when constructing a property",
151+
),
129152
};
130153

131154
PyObject::new(
132155
PyObjectPayload::AnyRustValue {
133-
value: Box::new(payload)
156+
value: Box::new(payload),
134157
},
135158
self.ctx.readonly_property_type(),
136159
)
137160
}
138161
}
139162
}
140163

141-
142164
pub fn init(context: &PyContext) {
143165
extend_class!(context, &context.readonly_property_type, {
144166
"__get__" => context.new_rustfunc(PyReadOnlyPropertyRef::get),
@@ -173,20 +195,11 @@ pub fn init(context: &PyContext) {
173195
del self._x";
174196

175197
extend_class!(context, &context.property_type, {
176-
"__new__" => context.new_rustfunc(property_new),
198+
"__new__" => context.new_rustfunc(PyPropertyRef::new_property),
177199
"__doc__" => context.new_str(property_doc.to_string()),
178200

179201
"__get__" => context.new_rustfunc(PyPropertyRef::get),
180202
"__set__" => context.new_rustfunc(PyPropertyRef::set),
181203
"__delete__" => context.new_rustfunc(PyPropertyRef::delete),
182204
});
183205
}
184-
185-
fn property_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
186-
trace!("property.__new__ {:?}", args.args);
187-
arg_check!(vm, args, required = [(cls, None), (fget, None)]);
188-
189-
let py_obj = vm.ctx.new_instance(cls.clone(), None);
190-
vm.ctx.set_attr(&py_obj, "fget", fget.clone());
191-
Ok(py_obj)
192-
}

vm/src/obj/objtype.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@ pub fn init(context: &PyContext) {
5050

5151
context.set_attr(&type_type, "__call__", context.new_rustfunc(type_call));
5252
context.set_attr(&type_type, "__new__", context.new_rustfunc(type_new));
53-
context.set_attr(
54-
&type_type,
55-
"__mro__",
56-
context.new_property(type_mro),
57-
);
53+
context.set_attr(&type_type, "__mro__", context.new_property(type_mro));
5854
context.set_attr(&type_type, "__repr__", context.new_rustfunc(type_repr));
5955
context.set_attr(
6056
&type_type,
@@ -81,13 +77,7 @@ pub fn init(context: &PyContext) {
8177
}
8278

8379
fn type_mro(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
84-
arg_check!(
85-
vm,
86-
args,
87-
required = [
88-
(cls, Some(vm.ctx.type_type()))
89-
]
90-
);
80+
arg_check!(vm, args, required = [(cls, Some(vm.ctx.type_type()))]);
9181
match _mro(cls.clone()) {
9282
Some(mro) => Ok(vm.context().new_tuple(mro)),
9383
None => Err(vm.new_type_error("Only classes have an MRO.".to_string())),

vm/src/pyobject.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ impl PyContext {
192192
&dict_type,
193193
);
194194
let property_type = create_type("property", &type_type, &object_type, &dict_type);
195-
let readonly_property_type = create_type("readonly_property", &type_type, &object_type, &dict_type);
195+
let readonly_property_type =
196+
create_type("readonly_property", &type_type, &object_type, &dict_type);
196197
let super_type = create_type("super", &type_type, &object_type, &dict_type);
197198
let generator_type = create_type("generator", &type_type, &object_type, &dict_type);
198199
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
@@ -948,7 +949,6 @@ impl From<PyObjectRef> for PyFuncArgs {
948949
}
949950
}
950951

951-
952952
impl PyFuncArgs {
953953
pub fn new(mut args: Vec<PyObjectRef>, kwarg_names: Vec<String>) -> PyFuncArgs {
954954
let mut kwargs = vec![];

0 commit comments

Comments
 (0)