Add getset_descriptor

This commit is contained in:
Jeong YunWon
2020-02-02 21:43:24 +09:00
parent 78180ff8a4
commit 9f5cd17f2b
5 changed files with 83 additions and 2 deletions

View File

@@ -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;

71
vm/src/obj/objgetset.rs Normal file
View File

@@ -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<PyGetter>,
setter: Box<PySetter>,
// doc: Option<String>,
}
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<PyGetSet>;
impl PyBuiltinDescriptor for PyGetSet {
fn get(
zelf: PyRef<Self>,
obj: PyObjectRef,
_cls: OptionalArg<PyObjectRef>,
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);
}

View File

@@ -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)))
}

View File

@@ -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()
}

View File

@@ -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);