Skip to content

Commit 3562b8f

Browse files
committed
Store class attributes inside PyClass struct.
1 parent 9989795 commit 3562b8f

File tree

2 files changed

+42
-35
lines changed

2 files changed

+42
-35
lines changed

vm/src/obj/objtype.rs

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub struct PyClass {
2222
pub name: String,
2323
pub mro: Vec<PyClassRef>,
2424
pub subclasses: RefCell<Vec<PyWeak>>,
25+
pub attributes: RefCell<PyAttributes>,
2526
}
2627

2728
impl fmt::Display for PyClass {
@@ -149,6 +150,25 @@ impl PyClassRef {
149150
}
150151
}
151152

153+
fn set_attr(
154+
self,
155+
attr_name: PyStringRef,
156+
value: PyObjectRef,
157+
vm: &VirtualMachine,
158+
) -> PyResult<()> {
159+
if let Some(attr) = class_get_attr(&self.type_pyref(), &attr_name.value) {
160+
if let Some(descriptor) = class_get_attr(&attr.type_pyref(), "__set__") {
161+
vm.invoke(descriptor, vec![attr, self.into_object(), value])?;
162+
return Ok(());
163+
}
164+
}
165+
166+
self.attributes
167+
.borrow_mut()
168+
.insert(attr_name.to_string(), value);
169+
Ok(())
170+
}
171+
152172
fn subclasses(self, _vm: &VirtualMachine) -> PyList {
153173
let mut subclasses = self.subclasses.borrow_mut();
154174
subclasses.retain(|x| x.upgrade().is_some());
@@ -181,6 +201,7 @@ pub fn init(ctx: &PyContext) {
181201
"__repr__" => ctx.new_rustfunc(PyClassRef::repr),
182202
"__prepare__" => ctx.new_rustfunc(PyClassRef::prepare),
183203
"__getattribute__" => ctx.new_rustfunc(PyClassRef::getattribute),
204+
"__setattr__" => ctx.new_rustfunc(PyClassRef::set_attr),
184205
"__subclasses__" => ctx.new_rustfunc(PyClassRef::subclasses),
185206
"__getattribute__" => ctx.new_rustfunc(PyClassRef::getattribute),
186207
"__instancecheck__" => ctx.new_rustfunc(PyClassRef::instance_check),
@@ -260,45 +281,26 @@ pub fn type_call(class: PyClassRef, args: Args, kwargs: KwArgs, vm: &VirtualMach
260281
Ok(obj)
261282
}
262283

263-
// Very private helper function for class_get_attr
264-
fn class_get_attr_in_dict(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
265-
if let Some(ref dict) = class.as_object().dict {
266-
dict.borrow().get(attr_name).cloned()
267-
} else {
268-
panic!("Only classes should be in MRO!");
269-
}
270-
}
271-
272-
// Very private helper function for class_has_attr
273-
fn class_has_attr_in_dict(class: &PyClassRef, attr_name: &str) -> bool {
274-
if let Some(ref dict) = class.as_object().dict {
275-
dict.borrow().contains_key(attr_name)
276-
} else {
277-
panic!("All classes are expected to have dicts!");
278-
}
279-
}
280-
281284
// This is the internal get_attr implementation for fast lookup on a class.
282-
pub fn class_get_attr(zelf: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
283-
let mro = &zelf.mro;
284-
if let Some(item) = class_get_attr_in_dict(zelf, attr_name) {
285+
pub fn class_get_attr(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
286+
if let Some(item) = class.attributes.borrow().get(attr_name).cloned() {
285287
return Some(item);
286288
}
287-
for class in mro {
288-
if let Some(item) = class_get_attr_in_dict(class, attr_name) {
289+
for class in &class.mro {
290+
if let Some(item) = class.attributes.borrow().get(attr_name).cloned() {
289291
return Some(item);
290292
}
291293
}
292294
None
293295
}
294296

295297
// This is the internal has_attr implementation for fast lookup on a class.
296-
pub fn class_has_attr(zelf: &PyClassRef, attr_name: &str) -> bool {
297-
class_has_attr_in_dict(zelf, attr_name)
298-
|| zelf
298+
pub fn class_has_attr(class: &PyClassRef, attr_name: &str) -> bool {
299+
class.attributes.borrow().contains_key(attr_name)
300+
|| class
299301
.mro
300302
.iter()
301-
.any(|d| class_has_attr_in_dict(d, attr_name))
303+
.any(|c| c.attributes.borrow().contains_key(attr_name))
302304
}
303305

304306
pub fn get_attributes(cls: PyClassRef) -> PyAttributes {
@@ -309,10 +311,8 @@ pub fn get_attributes(cls: PyClassRef) -> PyAttributes {
309311
base_classes.reverse();
310312

311313
for bc in base_classes {
312-
if let Some(ref dict) = &bc.as_object().dict {
313-
for (name, value) in dict.borrow().iter() {
314-
attributes.insert(name.to_string(), value.clone());
315-
}
314+
for (name, value) in bc.attributes.borrow().iter() {
315+
attributes.insert(name.to_string(), value.clone());
316316
}
317317
}
318318

@@ -374,8 +374,9 @@ pub fn new(
374374
name: String::from(name),
375375
mro,
376376
subclasses: RefCell::new(vec![]),
377+
attributes: RefCell::new(dict),
377378
},
378-
dict: Some(RefCell::new(dict)),
379+
dict: None,
379380
typ,
380381
}
381382
.into_ref();

vm/src/pyobject.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,22 +186,24 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
186186
let (type_type, object_type) = unsafe {
187187
let object_type = PyObject {
188188
typ: mem::uninitialized(), // !
189-
dict: Some(RefCell::new(PyAttributes::new())),
189+
dict: None,
190190
payload: PyClass {
191191
name: String::from("object"),
192192
mro: vec![],
193193
subclasses: RefCell::new(vec![]),
194+
attributes: RefCell::new(PyAttributes::new()),
194195
},
195196
}
196197
.into_ref();
197198

198199
let type_type = PyObject {
199200
typ: mem::uninitialized(), // !
200-
dict: Some(RefCell::new(PyAttributes::new())),
201+
dict: None,
201202
payload: PyClass {
202203
name: String::from("type"),
203204
mro: vec![object_type.clone().downcast().unwrap()],
204205
subclasses: RefCell::new(vec![]),
206+
attributes: RefCell::new(PyAttributes::new()),
205207
},
206208
}
207209
.into_ref();
@@ -655,7 +657,11 @@ impl PyContext {
655657
value: V,
656658
) {
657659
let obj = obj.into();
658-
if let Some(PyModule { ref dict, .. }) = obj.payload::<PyModule>() {
660+
if let Some(PyClass { ref attributes, .. }) = obj.payload::<PyClass>() {
661+
attributes
662+
.borrow_mut()
663+
.insert(attr_name.to_string(), value.into());
664+
} else if let Some(PyModule { ref dict, .. }) = obj.payload::<PyModule>() {
659665
dict.set_item(self, attr_name, value.into())
660666
} else if let Some(ref dict) = obj.dict {
661667
dict.borrow_mut()

0 commit comments

Comments
 (0)