From e7b39bdc8ad9775eb4621bd1b890f936ff9963e0 Mon Sep 17 00:00:00 2001 From: Moreal Date: Tue, 13 Sep 2022 22:56:31 +0900 Subject: [PATCH] Implement MemberDescrObject setter --- derive/src/pyclass.rs | 2 +- vm/src/builtins/descriptor.rs | 53 +++++++++++++++++++++++++++++++++++ vm/src/builtins/type.rs | 7 ++++- vm/src/object/core.rs | 18 ++++++++---- vm/src/vm/context.rs | 7 ++++- 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index 46c3af828..832cbe5af 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -694,7 +694,7 @@ where quote_spanned! { ident.span() => class.set_str_attr( #py_name, - ctx.new_member(#py_name, Self::#ident, class), + ctx.new_member(#py_name, Self::#ident, None, class), ctx, ); } diff --git a/vm/src/builtins/descriptor.rs b/vm/src/builtins/descriptor.rs index 57644b313..db8200790 100644 --- a/vm/src/builtins/descriptor.rs +++ b/vm/src/builtins/descriptor.rs @@ -1,6 +1,7 @@ use super::{PyStr, PyType, PyTypeRef}; use crate::{ class::PyClassImpl, + function::PySetterValue, types::{Constructor, GetDescriptor, Unconstructible}, AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, }; @@ -18,15 +19,23 @@ pub enum MemberKind { ObjectEx = 16, } +pub type MemberSetterFunc = Option PyResult<()>>; + pub enum MemberGetter { Getter(fn(&VirtualMachine, PyObjectRef) -> PyResult), Offset(usize), } +pub enum MemberSetter { + Setter(MemberSetterFunc), + Offset(usize), +} + pub struct MemberDef { pub name: String, pub kind: MemberKind, pub getter: MemberGetter, + pub setter: MemberSetter, pub doc: Option, } @@ -37,6 +46,21 @@ impl MemberDef { MemberGetter::Offset(offset) => get_slot_from_object(obj, offset, self, vm), } } + + fn set( + &self, + obj: PyObjectRef, + value: PySetterValue, + vm: &VirtualMachine, + ) -> PyResult<()> { + match self.setter { + MemberSetter::Setter(setter) => match setter { + Some(setter) => (setter)(vm, obj, value), + None => Err(vm.new_attribute_error("readonly attribute".to_string())), + }, + MemberSetter::Offset(offset) => set_slot_at_object(obj, offset, self, value, vm), + } + } } impl std::fmt::Debug for MemberDef { @@ -103,6 +127,17 @@ impl MemberDescrObject { qualname.to_owned() }) } + + #[pyslot] + fn descr_set( + zelf: PyObjectRef, + obj: PyObjectRef, + value: PySetterValue, + vm: &VirtualMachine, + ) -> PyResult<()> { + let zelf = Self::_zelf(zelf, vm)?; + zelf.member.set(obj, value, vm) + } } // PyMember_GetOne @@ -124,6 +159,24 @@ fn get_slot_from_object( Ok(slot) } +// PyMember_SetOne +fn set_slot_at_object( + obj: PyObjectRef, + offset: usize, + member: &MemberDef, + value: PySetterValue, + _vm: &VirtualMachine, +) -> PyResult<()> { + match member.kind { + MemberKind::ObjectEx => match value { + PySetterValue::Assign(v) => obj.set_slot(offset, Some(v)), + PySetterValue::Delete => obj.set_slot(offset, None), + }, + } + + Ok(()) +} + impl Unconstructible for MemberDescrObject {} impl GetDescriptor for MemberDescrObject { diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 314eecd12..a5daf21b5 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -4,7 +4,11 @@ use super::{ }; use crate::{ builtins::PyBaseExceptionRef, - builtins::{descriptor::MemberGetter, function::PyCellRef, tuple::PyTupleTyped}, + builtins::{ + descriptor::{MemberGetter, MemberSetter}, + function::PyCellRef, + tuple::PyTupleTyped, + }, class::{PyClassImpl, StaticType}, convert::ToPyObject, function::{FuncArgs, KwArgs, OptionalArg, PySetterValue}, @@ -689,6 +693,7 @@ impl PyType { name: member.to_string(), kind: MemberKind::ObjectEx, getter: MemberGetter::Offset(offset), + setter: MemberSetter::Offset(offset), doc: None, }; let member_descriptor: PyRef = vm.new_pyref(MemberDescrObject { diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index 79b40417a..94bd4151d 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -25,6 +25,7 @@ use crate::{ builtins::{PyDictRef, PyTypeRef}, vm::VirtualMachine, }; +use itertools::Itertools; use std::{ any::TypeId, borrow::Borrow, @@ -115,7 +116,7 @@ struct PyInner { weak_list: WeakRefList, payload: T, - slots: Vec>, + slots: Box<[PyRwLock>]>, } impl fmt::Debug for PyInner { @@ -436,7 +437,10 @@ impl PyInner { dict: dict.map(InstanceDict::new), weak_list: WeakRefList::new(), payload, - slots: vec![None; member_count], + slots: std::iter::repeat_with(|| PyRwLock::new(None)) + .take(member_count) + .collect_vec() + .into_boxed_slice(), }) } } @@ -799,7 +803,11 @@ impl PyObject { } pub(crate) fn get_slot(&self, offset: usize) -> Option { - self.0.slots[offset].clone() + self.0.slots[offset].read().clone() + } + + pub(crate) fn set_slot(&self, offset: usize, value: Option) { + *self.0.slots[offset].write() = value; } } @@ -1131,7 +1139,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) { dict: None, weak_list: WeakRefList::new(), payload: type_payload, - slots: Vec::new(), + slots: Box::new([]), }, Uninit { typ } ))); @@ -1143,7 +1151,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) { dict: None, weak_list: WeakRefList::new(), payload: object_payload, - slots: Vec::new(), + slots: Box::new([]), }, Uninit { typ }, ))); diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 286b0dfba..8482e5f9f 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -3,7 +3,10 @@ use crate::{ builtinfunc::{PyBuiltinFunction, PyBuiltinMethod, PyNativeFuncDef}, bytes, code::{self, PyCode}, - descriptor::{DescrObject, MemberDef, MemberDescrObject, MemberGetter, MemberKind}, + descriptor::{ + DescrObject, MemberDef, MemberDescrObject, MemberGetter, MemberKind, MemberSetter, + MemberSetterFunc, + }, getset::PyGetSet, object, pystr, type_::PyAttributes, @@ -458,12 +461,14 @@ impl Context { &self, name: &str, getter: fn(&VirtualMachine, PyObjectRef) -> PyResult, + setter: MemberSetterFunc, class: &'static Py, ) -> PyRef { let member_def = MemberDef { name: name.to_owned(), kind: MemberKind::ObjectEx, getter: MemberGetter::Getter(getter), + setter: MemberSetter::Setter(setter), doc: None, }; let member_descriptor = MemberDescrObject {