forked from Rust-related/RustPython
wip descr_set
This commit is contained in:
@@ -303,29 +303,37 @@ impl PyGetSet {
|
||||
impl PyGetSet {
|
||||
// Descriptor methods
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(ref f) = self.setter {
|
||||
f(vm, obj, value)
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"attribute '{}' of '{}' objects is not writable",
|
||||
self.name,
|
||||
obj.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn delete(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(ref f) = self.deleter {
|
||||
f(vm, obj)
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"attribute '{}' of '{}' objects is not writable",
|
||||
self.name,
|
||||
obj.class().name
|
||||
)))
|
||||
#[pyslot]
|
||||
fn descr_set(
|
||||
zelf: PyObjectRef,
|
||||
obj: PyObjectRef,
|
||||
value: Option<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let zelf = PyRef::<Self>::try_from_object(vm, zelf)?;
|
||||
match value {
|
||||
Some(value) => {
|
||||
if let Some(ref f) = zelf.setter {
|
||||
f(vm, obj, value)
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"attribute '{}' of '{}' objects is not writable",
|
||||
zelf.name,
|
||||
obj.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Some(ref f) = zelf.deleter {
|
||||
f(vm, obj)
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"attribute '{}' of '{}' objects is not writable",
|
||||
zelf.name,
|
||||
obj.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,8 +144,9 @@ impl PyBaseObject {
|
||||
#[pymethod(magic)]
|
||||
fn delattr(obj: PyObjectRef, attr_name: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(attr) = obj.get_class_attr(attr_name.borrow_value()) {
|
||||
if let Some(descriptor) = attr.get_class_attr("__delete__") {
|
||||
return vm.invoke(&descriptor, vec![attr, obj]).map(|_| ());
|
||||
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
|
||||
if let Some(descriptor) = descr_set {
|
||||
return descriptor(attr, obj, None, vm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,8 +293,9 @@ pub(crate) fn setattr(
|
||||
vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value);
|
||||
|
||||
if let Some(attr) = obj.get_class_attr(attr_name.borrow_value()) {
|
||||
if let Some(descriptor) = attr.get_class_attr("__set__") {
|
||||
return vm.invoke(&descriptor, vec![attr, obj, value]).map(|_| ());
|
||||
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
|
||||
if let Some(descriptor) = descr_set {
|
||||
return descriptor(attr, obj, Some(value), vm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::common::lock::PyRwLock;
|
||||
use super::pytype::PyTypeRef;
|
||||
use crate::function::FuncArgs;
|
||||
use crate::pyobject::{
|
||||
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::slots::SlotDescriptor;
|
||||
use crate::vm::VirtualMachine;
|
||||
@@ -111,21 +111,29 @@ impl PyProperty {
|
||||
|
||||
// Descriptor methods
|
||||
|
||||
#[pymethod(name = "__set__")]
|
||||
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(ref setter) = self.setter.read().as_ref() {
|
||||
vm.invoke(setter, vec![obj, value])
|
||||
} else {
|
||||
Err(vm.new_attribute_error("can't set attribute".to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__delete__")]
|
||||
fn delete(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(ref deleter) = self.deleter.read().as_ref() {
|
||||
vm.invoke(deleter, (obj,))
|
||||
} else {
|
||||
Err(vm.new_attribute_error("can't delete attribute".to_owned()))
|
||||
#[pyslot]
|
||||
fn descr_set(
|
||||
zelf: PyObjectRef,
|
||||
obj: PyObjectRef,
|
||||
value: Option<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let zelf = PyRef::<Self>::try_from_object(vm, zelf)?;
|
||||
match value {
|
||||
Some(value) => {
|
||||
if let Some(ref setter) = zelf.setter.read().as_ref() {
|
||||
vm.invoke(setter, vec![obj, value]).map(drop)
|
||||
} else {
|
||||
Err(vm.new_attribute_error("can't set attribute".to_owned()))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Some(ref deleter) = zelf.deleter.read().as_ref() {
|
||||
vm.invoke(deleter, (obj,)).map(drop)
|
||||
} else {
|
||||
Err(vm.new_attribute_error("can't delete attribute".to_owned()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,16 @@ impl PyType {
|
||||
} as _;
|
||||
update_slot!(descr_get, func);
|
||||
}
|
||||
"__set__" | "__delete__" => {
|
||||
let func: slots::DescrSetFunc = |zelf, obj, value, vm| {
|
||||
match value {
|
||||
Some(val) => vm.call_method(&zelf, "__set__", (obj, val)),
|
||||
None => vm.call_method(&zelf, "__delete__", (obj,)),
|
||||
}
|
||||
.map(drop)
|
||||
} as _;
|
||||
update_slot!(descr_set, func);
|
||||
}
|
||||
"__hash__" => {
|
||||
let func: slots::HashFunc = |zelf, vm| {
|
||||
let magic = get_class_magic(&zelf, "__hash__");
|
||||
@@ -347,9 +357,9 @@ impl PyType {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
if let Some(attr) = zelf.get_class_attr(attr_name.borrow_value()) {
|
||||
if let Some(ref descriptor) = attr.get_class_attr("__set__") {
|
||||
vm.invoke(descriptor, (attr, zelf, value))?;
|
||||
return Ok(());
|
||||
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
|
||||
if let Some(descriptor) = descr_set {
|
||||
return descriptor(attr, zelf.into_object(), Some(value), vm);
|
||||
}
|
||||
}
|
||||
let attr_name = attr_name.borrow_value();
|
||||
@@ -364,8 +374,9 @@ impl PyType {
|
||||
#[pymethod(magic)]
|
||||
fn delattr(zelf: PyRef<Self>, attr_name: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(attr) = zelf.get_class_attr(attr_name.borrow_value()) {
|
||||
if let Some(ref descriptor) = attr.get_class_attr("__delete__") {
|
||||
return vm.invoke(descriptor, (attr, zelf)).map(|_| ());
|
||||
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
|
||||
if let Some(set) = descr_set {
|
||||
return set(attr, zelf.into_object(), None, vm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,7 +505,7 @@ impl PyType {
|
||||
)
|
||||
.map_err(|e| vm.new_type_error(e))?;
|
||||
|
||||
vm.ctx.add_tp_new_wrapper(&typ);
|
||||
vm.ctx.add_slot_wrappers(&typ);
|
||||
|
||||
// avoid deadlock
|
||||
let attributes = typ
|
||||
@@ -558,10 +569,11 @@ impl SlotGetattro for PyType {
|
||||
|
||||
if let Some(ref attr) = mcl_attr {
|
||||
let attr_class = attr.class();
|
||||
if attr_class.has_attr("__set__") {
|
||||
if let Some(ref descr_get) =
|
||||
attr_class.mro_find_map(|cls| cls.slots.descr_get.load())
|
||||
{
|
||||
if attr_class
|
||||
.mro_find_map(|cls| cls.slots.descr_set.load())
|
||||
.is_some()
|
||||
{
|
||||
if let Some(descr_get) = attr_class.mro_find_map(|cls| cls.slots.descr_get.load()) {
|
||||
let mcl = PyLease::into_pyref(mcl).into_object();
|
||||
return descr_get(attr.clone(), Some(zelf.into_object()), Some(mcl), vm);
|
||||
}
|
||||
@@ -644,19 +656,22 @@ fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -
|
||||
let cls = obj.clone_class();
|
||||
match find_base_dict_descr(&cls, vm) {
|
||||
Some(descr) => {
|
||||
descr
|
||||
.get_class_attr("__set__")
|
||||
.map(|set| vm.invoke(&set, vec![descr, obj, value]))
|
||||
.unwrap_or_else(|| {
|
||||
Err(vm.new_type_error(format!(
|
||||
let descr_set = descr
|
||||
.class()
|
||||
.mro_find_map(|cls| cls.slots.descr_set.load())
|
||||
.ok_or_else(|| {
|
||||
vm.new_type_error(format!(
|
||||
"this __dict__ descriptor does not support '{}' objects",
|
||||
cls.name
|
||||
)))
|
||||
))
|
||||
})?;
|
||||
descr_set(descr, obj, Some(value), vm)
|
||||
}
|
||||
None => {
|
||||
object::object_set_dict(obj, PyDictRef::try_from_object(vm, value)?, vm)?;
|
||||
Ok(())
|
||||
}
|
||||
None => object::object_set_dict(obj, PyDictRef::try_from_object(vm, value)?, vm)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,7 +30,7 @@ macro_rules! py_class {
|
||||
$($crate::py_class!(@extract_slots($ctx, &mut slots, $name, $value));)*
|
||||
let py_class = $ctx.new_class($class_name, $class_base, slots);
|
||||
$($crate::py_class!(@extract_attrs($ctx, &py_class, $name, $value));)*
|
||||
$ctx.add_tp_new_wrapper(&py_class);
|
||||
$ctx.add_slot_wrappers(&py_class);
|
||||
py_class
|
||||
}
|
||||
};
|
||||
@@ -55,7 +55,7 @@ macro_rules! extend_class {
|
||||
$(
|
||||
$class.set_str_attr($name, $value);
|
||||
)*
|
||||
$ctx.add_tp_new_wrapper(&$class);
|
||||
$ctx.add_slot_wrappers(&$class);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -359,7 +359,7 @@ impl PyContext {
|
||||
PyObject::new(object::PyBaseObject, class, dict)
|
||||
}
|
||||
|
||||
pub fn add_tp_new_wrapper(&self, ty: &PyTypeRef) {
|
||||
pub fn add_slot_wrappers(&self, ty: &PyTypeRef) {
|
||||
if !ty.attributes.read().contains_key("__new__") {
|
||||
let new_wrapper =
|
||||
self.new_bound_method(self.tp_new_wrapper.clone(), ty.clone().into_object());
|
||||
@@ -1075,7 +1075,7 @@ pub trait PyClassImpl: PyClassDef {
|
||||
);
|
||||
}
|
||||
Self::impl_extend_class(ctx, class);
|
||||
ctx.add_tp_new_wrapper(&class);
|
||||
ctx.add_slot_wrappers(&class);
|
||||
if let Some(doc) = Self::DOC {
|
||||
class.set_str_attr("__doc__", ctx.new_str(doc));
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ pub(crate) type GenericMethod = fn(&PyObjectRef, FuncArgs, &VirtualMachine) -> P
|
||||
pub(crate) type DelFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult<()>;
|
||||
pub(crate) type DescrGetFunc =
|
||||
fn(PyObjectRef, Option<PyObjectRef>, Option<PyObjectRef>, &VirtualMachine) -> PyResult;
|
||||
pub(crate) type DescrSetFunc =
|
||||
fn(PyObjectRef, PyObjectRef, Option<PyObjectRef>, &VirtualMachine) -> PyResult<()>;
|
||||
pub(crate) type HashFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult<PyHash>;
|
||||
pub(crate) type CmpFunc = fn(
|
||||
&PyObjectRef,
|
||||
@@ -67,6 +69,7 @@ pub struct PyTypeSlots {
|
||||
pub del: AtomicCell<Option<DelFunc>>,
|
||||
pub call: AtomicCell<Option<GenericMethod>>,
|
||||
pub descr_get: AtomicCell<Option<DescrGetFunc>>,
|
||||
pub descr_set: AtomicCell<Option<DescrSetFunc>>,
|
||||
pub hash: AtomicCell<Option<HashFunc>>,
|
||||
pub cmp: AtomicCell<Option<CmpFunc>>,
|
||||
pub getattro: AtomicCell<Option<GetattroFunc>>,
|
||||
|
||||
@@ -1259,7 +1259,10 @@ impl VirtualMachine {
|
||||
let descr_cls = descr.class();
|
||||
let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load());
|
||||
if let Some(descr_get) = descr_get {
|
||||
if descr_cls.has_attr("__set__") {
|
||||
if descr_cls
|
||||
.mro_find_map(|cls| cls.slots.descr_set.load())
|
||||
.is_some()
|
||||
{
|
||||
drop(descr_cls);
|
||||
let cls = PyLease::into_pyref(obj_cls).into_object();
|
||||
return descr_get(descr, Some(obj), Some(cls), self).map(Some);
|
||||
|
||||
Reference in New Issue
Block a user