Skip to content

Commit 05e13b6

Browse files
authored
Merge pull request RustPython#4160 from moreal/pymember-setter
Implement `MemberDescrObject` setter
2 parents 768a8e5 + 27855a6 commit 05e13b6

File tree

6 files changed

+79
-12
lines changed

6 files changed

+79
-12
lines changed

Lib/test/test_functools.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,6 @@ def test_deepcopy(self):
272272
self.assertIsNot(f_copy.keywords, f.keywords)
273273
self.assertIsNot(f_copy.keywords['bar'], f.keywords['bar'])
274274

275-
# TODO: RUSTPYTHON
276-
@unittest.expectedFailure
277275
def test_setstate(self):
278276
f = self.partial(signature)
279277
f.__setstate__((capture, (1,), dict(a=10), dict(attr=[])))
@@ -309,8 +307,6 @@ def test_setstate_errors(self):
309307
self.assertRaises(TypeError, f.__setstate__, (capture, [], {}, None))
310308
self.assertRaises(TypeError, f.__setstate__, (capture, (), [], None))
311309

312-
# TODO: RUSTPYTHON
313-
@unittest.expectedFailure
314310
def test_setstate_subclasses(self):
315311
f = self.partial(signature)
316312
f.__setstate__((capture, MyTuple((1,)), MyDict(a=10), None))

derive/src/pyclass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ where
694694
quote_spanned! { ident.span() =>
695695
class.set_str_attr(
696696
#py_name,
697-
ctx.new_member(#py_name, Self::#ident, class),
697+
ctx.new_member(#py_name, Self::#ident, None, class),
698698
ctx,
699699
);
700700
}

vm/src/builtins/descriptor.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::{PyStr, PyType, PyTypeRef};
22
use crate::{
33
class::PyClassImpl,
4+
function::PySetterValue,
45
types::{Constructor, GetDescriptor, Unconstructible},
56
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
67
};
@@ -18,15 +19,23 @@ pub enum MemberKind {
1819
ObjectEx = 16,
1920
}
2021

22+
pub type MemberSetterFunc = Option<fn(&VirtualMachine, PyObjectRef, PySetterValue) -> PyResult<()>>;
23+
2124
pub enum MemberGetter {
2225
Getter(fn(&VirtualMachine, PyObjectRef) -> PyResult),
2326
Offset(usize),
2427
}
2528

29+
pub enum MemberSetter {
30+
Setter(MemberSetterFunc),
31+
Offset(usize),
32+
}
33+
2634
pub struct MemberDef {
2735
pub name: String,
2836
pub kind: MemberKind,
2937
pub getter: MemberGetter,
38+
pub setter: MemberSetter,
3039
pub doc: Option<String>,
3140
}
3241

@@ -37,6 +46,21 @@ impl MemberDef {
3746
MemberGetter::Offset(offset) => get_slot_from_object(obj, offset, self, vm),
3847
}
3948
}
49+
50+
fn set(
51+
&self,
52+
obj: PyObjectRef,
53+
value: PySetterValue<PyObjectRef>,
54+
vm: &VirtualMachine,
55+
) -> PyResult<()> {
56+
match self.setter {
57+
MemberSetter::Setter(setter) => match setter {
58+
Some(setter) => (setter)(vm, obj, value),
59+
None => Err(vm.new_attribute_error("readonly attribute".to_string())),
60+
},
61+
MemberSetter::Offset(offset) => set_slot_at_object(obj, offset, self, value, vm),
62+
}
63+
}
4064
}
4165

4266
impl std::fmt::Debug for MemberDef {
@@ -103,6 +127,17 @@ impl MemberDescrObject {
103127
qualname.to_owned()
104128
})
105129
}
130+
131+
#[pyslot]
132+
fn descr_set(
133+
zelf: PyObjectRef,
134+
obj: PyObjectRef,
135+
value: PySetterValue<PyObjectRef>,
136+
vm: &VirtualMachine,
137+
) -> PyResult<()> {
138+
let zelf = Self::_zelf(zelf, vm)?;
139+
zelf.member.set(obj, value, vm)
140+
}
106141
}
107142

108143
// PyMember_GetOne
@@ -124,6 +159,24 @@ fn get_slot_from_object(
124159
Ok(slot)
125160
}
126161

162+
// PyMember_SetOne
163+
fn set_slot_at_object(
164+
obj: PyObjectRef,
165+
offset: usize,
166+
member: &MemberDef,
167+
value: PySetterValue,
168+
_vm: &VirtualMachine,
169+
) -> PyResult<()> {
170+
match member.kind {
171+
MemberKind::ObjectEx => match value {
172+
PySetterValue::Assign(v) => obj.set_slot(offset, Some(v)),
173+
PySetterValue::Delete => obj.set_slot(offset, None),
174+
},
175+
}
176+
177+
Ok(())
178+
}
179+
127180
impl Unconstructible for MemberDescrObject {}
128181

129182
impl GetDescriptor for MemberDescrObject {

vm/src/builtins/type.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ use super::{
44
};
55
use crate::{
66
builtins::PyBaseExceptionRef,
7-
builtins::{descriptor::MemberGetter, function::PyCellRef, tuple::PyTupleTyped},
7+
builtins::{
8+
descriptor::{MemberGetter, MemberSetter},
9+
function::PyCellRef,
10+
tuple::PyTupleTyped,
11+
},
812
class::{PyClassImpl, StaticType},
913
convert::ToPyObject,
1014
function::{FuncArgs, KwArgs, OptionalArg, PySetterValue},
@@ -689,6 +693,7 @@ impl PyType {
689693
name: member.to_string(),
690694
kind: MemberKind::ObjectEx,
691695
getter: MemberGetter::Offset(offset),
696+
setter: MemberSetter::Offset(offset),
692697
doc: None,
693698
};
694699
let member_descriptor: PyRef<MemberDescrObject> = vm.new_pyref(MemberDescrObject {

vm/src/object/core.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::{
2525
builtins::{PyDictRef, PyTypeRef},
2626
vm::VirtualMachine,
2727
};
28+
use itertools::Itertools;
2829
use std::{
2930
any::TypeId,
3031
borrow::Borrow,
@@ -113,9 +114,9 @@ struct PyInner<T> {
113114
typ: PyRwLock<PyTypeRef>, // __class__ member
114115
dict: Option<InstanceDict>,
115116
weak_list: WeakRefList,
117+
slots: Box<[PyRwLock<Option<PyObjectRef>>]>,
116118

117119
payload: T,
118-
slots: Vec<Option<PyObjectRef>>,
119120
}
120121

121122
impl<T: fmt::Debug> fmt::Debug for PyInner<T> {
@@ -436,7 +437,10 @@ impl<T: PyObjectPayload> PyInner<T> {
436437
dict: dict.map(InstanceDict::new),
437438
weak_list: WeakRefList::new(),
438439
payload,
439-
slots: vec![None; member_count],
440+
slots: std::iter::repeat_with(|| PyRwLock::new(None))
441+
.take(member_count)
442+
.collect_vec()
443+
.into_boxed_slice(),
440444
})
441445
}
442446
}
@@ -799,7 +803,11 @@ impl PyObject {
799803
}
800804

801805
pub(crate) fn get_slot(&self, offset: usize) -> Option<PyObjectRef> {
802-
self.0.slots[offset].clone()
806+
self.0.slots[offset].read().clone()
807+
}
808+
809+
pub(crate) fn set_slot(&self, offset: usize, value: Option<PyObjectRef>) {
810+
*self.0.slots[offset].write() = value;
803811
}
804812
}
805813

@@ -1131,7 +1139,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
11311139
dict: None,
11321140
weak_list: WeakRefList::new(),
11331141
payload: type_payload,
1134-
slots: Vec::new(),
1142+
slots: Box::new([]),
11351143
},
11361144
Uninit { typ }
11371145
)));
@@ -1143,7 +1151,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
11431151
dict: None,
11441152
weak_list: WeakRefList::new(),
11451153
payload: object_payload,
1146-
slots: Vec::new(),
1154+
slots: Box::new([]),
11471155
},
11481156
Uninit { typ },
11491157
)));

vm/src/vm/context.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use crate::{
33
builtinfunc::{PyBuiltinFunction, PyBuiltinMethod, PyNativeFuncDef},
44
bytes,
55
code::{self, PyCode},
6-
descriptor::{DescrObject, MemberDef, MemberDescrObject, MemberGetter, MemberKind},
6+
descriptor::{
7+
DescrObject, MemberDef, MemberDescrObject, MemberGetter, MemberKind, MemberSetter,
8+
MemberSetterFunc,
9+
},
710
getset::PyGetSet,
811
object, pystr,
912
type_::PyAttributes,
@@ -458,12 +461,14 @@ impl Context {
458461
&self,
459462
name: &str,
460463
getter: fn(&VirtualMachine, PyObjectRef) -> PyResult,
464+
setter: MemberSetterFunc,
461465
class: &'static Py<PyType>,
462466
) -> PyRef<MemberDescrObject> {
463467
let member_def = MemberDef {
464468
name: name.to_owned(),
465469
kind: MemberKind::ObjectEx,
466470
getter: MemberGetter::Getter(getter),
471+
setter: MemberSetter::Setter(setter),
467472
doc: None,
468473
};
469474
let member_descriptor = MemberDescrObject {

0 commit comments

Comments
 (0)