Skip to content
Next Next commit
Add getset_descriptor
  • Loading branch information
youknowone committed Feb 5, 2020
commit 9f5cd17f2bc296ddf97c4e8311000234f8222d43
1 change: 1 addition & 0 deletions vm/src/obj/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
71 changes: 71 additions & 0 deletions vm/src/obj/objgetset.rs
Original file line number Diff line number Diff line change
@@ -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>,
Comment thread
youknowone marked this conversation as resolved.
Outdated
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);
}
4 changes: 2 additions & 2 deletions vm/src/obj/objobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
Expand Down
4 changes: 4 additions & 0 deletions vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
5 changes: 5 additions & 0 deletions vm/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -220,6 +223,7 @@ impl TypeZoo {
mappingproxy_type,
property_type,
readonly_property_type,
getset_type,
generator_type,
module_type,
namespace_type,
Expand Down Expand Up @@ -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);
Expand Down