From 9f5cd17f2bc296ddf97c4e8311000234f8222d43 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 2 Feb 2020 21:43:24 +0900 Subject: [PATCH] Add getset_descriptor --- vm/src/obj/mod.rs | 1 + vm/src/obj/objgetset.rs | 71 +++++++++++++++++++++++++++++++++++++++++ vm/src/obj/objobject.rs | 4 +-- vm/src/pyobject.rs | 4 +++ vm/src/types.rs | 5 +++ 5 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 vm/src/obj/objgetset.rs diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index 57233025d..af5d531d1 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -17,6 +17,7 @@ pub mod objfloat; pub mod objframe; pub mod objfunction; pub mod objgenerator; +pub mod objgetset; pub mod objint; pub mod objiter; pub mod objlist; diff --git a/vm/src/obj/objgetset.rs b/vm/src/obj/objgetset.rs new file mode 100644 index 000000000..e8ee40b67 --- /dev/null +++ b/vm/src/obj/objgetset.rs @@ -0,0 +1,71 @@ +/*! Python `attribute` descriptor class. (PyGetSet) + +*/ +use super::objtype::PyClassRef; +use crate::function::OptionalArg; +use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue}; +use crate::slots::PyBuiltinDescriptor; +use crate::vm::VirtualMachine; + +pub type PyGetter = dyn Fn(PyObjectRef, &VirtualMachine) -> PyResult; +pub type PySetter = dyn Fn(PyObjectRef, PyObjectRef, &VirtualMachine) -> PyResult<()>; + +#[pyclass] +pub struct PyGetSet { + // name: String, + getter: Box, + setter: Box, + // doc: Option, +} + +impl std::fmt::Debug for PyGetSet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "PyGetSet {{ getter: {:p}, setter: {:p} }}", + self.getter, self.setter + ) + } +} + +impl PyValue for PyGetSet { + fn class(vm: &VirtualMachine) -> PyClassRef { + vm.ctx.getset_type() + } +} + +pub type PyGetSetRef = PyRef; + +impl PyBuiltinDescriptor for PyGetSet { + fn get( + zelf: PyRef, + obj: PyObjectRef, + _cls: OptionalArg, + vm: &VirtualMachine, + ) -> PyResult { + (zelf.getter)(obj, vm) + } +} + +impl PyGetSet { + pub fn new(getter: &'static PyGetter, setter: &'static PySetter) -> Self { + Self { + getter: Box::new(getter), + setter: Box::new(setter), + } + } +} + +#[pyimpl(with(PyBuiltinDescriptor))] +impl PyGetSet { + // Descriptor methods + + #[pymethod(magic)] + fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + (self.setter)(obj, value, vm) + } +} + +pub(crate) fn init(context: &PyContext) { + PyGetSet::extend_class(context, &context.types.getset_type); +} diff --git a/vm/src/obj/objobject.rs b/vm/src/obj/objobject.rs index 671dcd9e6..bafec4abb 100644 --- a/vm/src/obj/objobject.rs +++ b/vm/src/obj/objobject.rs @@ -175,12 +175,12 @@ impl PyBaseObject { } #[pyproperty(name = "__class__")] - fn _class(obj: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef { + fn get_class(obj: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef { obj.class().into_object() } #[pyproperty(name = "__class__", setter)] - fn _set_class(instance: PyObjectRef, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { + fn set_class(instance: PyObjectRef, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { let type_repr = vm.to_pystr(&instance.class())?; Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr))) } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index db0df14a1..555d480bd 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -330,6 +330,10 @@ impl PyContext { self.types.readonly_property_type.clone() } + pub fn getset_type(&self) -> PyClassRef { + self.types.getset_type.clone() + } + pub fn classmethod_type(&self) -> PyClassRef { self.types.classmethod_type.clone() } diff --git a/vm/src/types.rs b/vm/src/types.rs index 2c9d94026..a81755a01 100644 --- a/vm/src/types.rs +++ b/vm/src/types.rs @@ -14,6 +14,7 @@ use crate::obj::objfloat; use crate::obj::objframe; use crate::obj::objfunction; use crate::obj::objgenerator; +use crate::obj::objgetset; use crate::obj::objint; use crate::obj::objiter; use crate::obj::objlist; @@ -94,6 +95,7 @@ pub struct TypeZoo { pub method_descriptor_type: PyClassRef, pub property_type: PyClassRef, pub readonly_property_type: PyClassRef, + pub getset_type: PyClassRef, pub module_type: PyClassRef, pub namespace_type: PyClassRef, pub bound_method_type: PyClassRef, @@ -125,6 +127,7 @@ impl TypeZoo { let method_descriptor_type = create_type("method_descriptor", &type_type, &object_type); let property_type = create_type("property", &type_type, &object_type); let readonly_property_type = create_type("readonly_property", &type_type, &object_type); + let getset_type = create_type("getset_descriptor", &type_type, &object_type); let super_type = create_type("super", &type_type, &object_type); let weakref_type = create_type("ref", &type_type, &object_type); let weakproxy_type = create_type("weakproxy", &type_type, &object_type); @@ -220,6 +223,7 @@ impl TypeZoo { mappingproxy_type, property_type, readonly_property_type, + getset_type, generator_type, module_type, namespace_type, @@ -381,6 +385,7 @@ pub fn initialize_types(context: &PyContext) { objbytes::init(&context); objbytearray::init(&context); objproperty::init(&context); + objgetset::init(&context); objmemory::init(&context); objstr::init(&context); objrange::init(&context);