Skip to content

Commit 9f5cd17

Browse files
committed
Add getset_descriptor
1 parent 78180ff commit 9f5cd17

File tree

5 files changed

+83
-2
lines changed

5 files changed

+83
-2
lines changed

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod objfloat;
1717
pub mod objframe;
1818
pub mod objfunction;
1919
pub mod objgenerator;
20+
pub mod objgetset;
2021
pub mod objint;
2122
pub mod objiter;
2223
pub mod objlist;

vm/src/obj/objgetset.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*! Python `attribute` descriptor class. (PyGetSet)
2+
3+
*/
4+
use super::objtype::PyClassRef;
5+
use crate::function::OptionalArg;
6+
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
7+
use crate::slots::PyBuiltinDescriptor;
8+
use crate::vm::VirtualMachine;
9+
10+
pub type PyGetter = dyn Fn(PyObjectRef, &VirtualMachine) -> PyResult;
11+
pub type PySetter = dyn Fn(PyObjectRef, PyObjectRef, &VirtualMachine) -> PyResult<()>;
12+
13+
#[pyclass]
14+
pub struct PyGetSet {
15+
// name: String,
16+
getter: Box<PyGetter>,
17+
setter: Box<PySetter>,
18+
// doc: Option<String>,
19+
}
20+
21+
impl std::fmt::Debug for PyGetSet {
22+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23+
write!(
24+
f,
25+
"PyGetSet {{ getter: {:p}, setter: {:p} }}",
26+
self.getter, self.setter
27+
)
28+
}
29+
}
30+
31+
impl PyValue for PyGetSet {
32+
fn class(vm: &VirtualMachine) -> PyClassRef {
33+
vm.ctx.getset_type()
34+
}
35+
}
36+
37+
pub type PyGetSetRef = PyRef<PyGetSet>;
38+
39+
impl PyBuiltinDescriptor for PyGetSet {
40+
fn get(
41+
zelf: PyRef<Self>,
42+
obj: PyObjectRef,
43+
_cls: OptionalArg<PyObjectRef>,
44+
vm: &VirtualMachine,
45+
) -> PyResult {
46+
(zelf.getter)(obj, vm)
47+
}
48+
}
49+
50+
impl PyGetSet {
51+
pub fn new(getter: &'static PyGetter, setter: &'static PySetter) -> Self {
52+
Self {
53+
getter: Box::new(getter),
54+
setter: Box::new(setter),
55+
}
56+
}
57+
}
58+
59+
#[pyimpl(with(PyBuiltinDescriptor))]
60+
impl PyGetSet {
61+
// Descriptor methods
62+
63+
#[pymethod(magic)]
64+
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
65+
(self.setter)(obj, value, vm)
66+
}
67+
}
68+
69+
pub(crate) fn init(context: &PyContext) {
70+
PyGetSet::extend_class(context, &context.types.getset_type);
71+
}

vm/src/obj/objobject.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,12 @@ impl PyBaseObject {
175175
}
176176

177177
#[pyproperty(name = "__class__")]
178-
fn _class(obj: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef {
178+
fn get_class(obj: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef {
179179
obj.class().into_object()
180180
}
181181

182182
#[pyproperty(name = "__class__", setter)]
183-
fn _set_class(instance: PyObjectRef, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
183+
fn set_class(instance: PyObjectRef, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
184184
let type_repr = vm.to_pystr(&instance.class())?;
185185
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
186186
}

vm/src/pyobject.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ impl PyContext {
330330
self.types.readonly_property_type.clone()
331331
}
332332

333+
pub fn getset_type(&self) -> PyClassRef {
334+
self.types.getset_type.clone()
335+
}
336+
333337
pub fn classmethod_type(&self) -> PyClassRef {
334338
self.types.classmethod_type.clone()
335339
}

vm/src/types.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::obj::objfloat;
1414
use crate::obj::objframe;
1515
use crate::obj::objfunction;
1616
use crate::obj::objgenerator;
17+
use crate::obj::objgetset;
1718
use crate::obj::objint;
1819
use crate::obj::objiter;
1920
use crate::obj::objlist;
@@ -94,6 +95,7 @@ pub struct TypeZoo {
9495
pub method_descriptor_type: PyClassRef,
9596
pub property_type: PyClassRef,
9697
pub readonly_property_type: PyClassRef,
98+
pub getset_type: PyClassRef,
9799
pub module_type: PyClassRef,
98100
pub namespace_type: PyClassRef,
99101
pub bound_method_type: PyClassRef,
@@ -125,6 +127,7 @@ impl TypeZoo {
125127
let method_descriptor_type = create_type("method_descriptor", &type_type, &object_type);
126128
let property_type = create_type("property", &type_type, &object_type);
127129
let readonly_property_type = create_type("readonly_property", &type_type, &object_type);
130+
let getset_type = create_type("getset_descriptor", &type_type, &object_type);
128131
let super_type = create_type("super", &type_type, &object_type);
129132
let weakref_type = create_type("ref", &type_type, &object_type);
130133
let weakproxy_type = create_type("weakproxy", &type_type, &object_type);
@@ -220,6 +223,7 @@ impl TypeZoo {
220223
mappingproxy_type,
221224
property_type,
222225
readonly_property_type,
226+
getset_type,
223227
generator_type,
224228
module_type,
225229
namespace_type,
@@ -381,6 +385,7 @@ pub fn initialize_types(context: &PyContext) {
381385
objbytes::init(&context);
382386
objbytearray::init(&context);
383387
objproperty::init(&context);
388+
objgetset::init(&context);
384389
objmemory::init(&context);
385390
objstr::init(&context);
386391
objrange::init(&context);

0 commit comments

Comments
 (0)