Skip to content

Commit 1e39512

Browse files
committed
Convert _mro to iterator.
1 parent 3711881 commit 1e39512

File tree

2 files changed

+65
-39
lines changed

2 files changed

+65
-39
lines changed

vm/src/obj/objobject.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::objlist::PyList;
12
use super::objstr;
23
use super::objtype;
34
use crate::obj::objproperty::PropertyBuilder;
@@ -133,16 +134,13 @@ fn object_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
133134
Ok(vm.new_str(format!("<{} object at 0x{:x}>", type_name, address)))
134135
}
135136

136-
pub fn object_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
137-
arg_check!(vm, args, required = [(obj, None)]);
138-
137+
pub fn object_dir(obj: PyObjectRef, vm: &mut VirtualMachine) -> PyList {
139138
let attributes = get_attributes(&obj);
140-
Ok(vm.ctx.new_list(
141-
attributes
142-
.keys()
143-
.map(|k| vm.ctx.new_str(k.to_string()))
144-
.collect(),
145-
))
139+
let attributes: Vec<PyObjectRef> = attributes
140+
.keys()
141+
.map(|k| vm.ctx.new_str(k.to_string()))
142+
.collect();
143+
PyList::from(attributes)
146144
}
147145

148146
fn object_format(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -260,7 +258,7 @@ fn object_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
260258

261259
pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes {
262260
// Get class attributes:
263-
let mut attributes = objtype::get_attributes(&obj.typ());
261+
let mut attributes = objtype::get_attributes(obj.type_pyref());
264262

265263
// Get instance attributes:
266264
if let Some(dict) = &obj.dict {

vm/src/obj/objtype.rs

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ use std::cell::RefCell;
22
use std::collections::HashMap;
33

44
use crate::pyobject::{
5-
AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectRef,
6-
PyRef, PyResult, PyValue, TypeProtocol,
5+
AttributeProtocol, FromPyObjectRef, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject,
6+
PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
77
};
88
use crate::vm::VirtualMachine;
99

1010
use super::objdict;
11+
use super::objlist::PyList;
1112
use super::objstr;
13+
use super::objtuple::PyTuple;
1214

1315
#[derive(Clone, Debug)]
1416
pub struct PyClass {
@@ -24,6 +26,41 @@ impl PyValue for PyClass {
2426
}
2527
}
2628

29+
struct IterMro<'a> {
30+
cls: &'a PyClassRef,
31+
offset: Option<usize>,
32+
}
33+
34+
impl<'a> Iterator for IterMro<'a> {
35+
type Item = &'a PyObjectRef;
36+
37+
fn next(&mut self) -> Option<Self::Item> {
38+
match self.offset {
39+
None => {
40+
self.offset = Some(0);
41+
Some(&self.cls.as_object())
42+
}
43+
Some(offset) => {
44+
if offset < self.cls.mro.len() {
45+
self.offset = Some(offset + 1);
46+
Some(&self.cls.mro[offset])
47+
} else {
48+
None
49+
}
50+
}
51+
}
52+
}
53+
}
54+
55+
impl PyClassRef {
56+
fn iter_mro(&self) -> IterMro {
57+
IterMro {
58+
cls: self,
59+
offset: None,
60+
}
61+
}
62+
}
63+
2764
/*
2865
* The magical type type
2966
*/
@@ -60,22 +97,12 @@ pub fn init(ctx: &PyContext) {
6097
});
6198
}
6299

63-
fn type_mro(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
64-
arg_check!(vm, args, required = [(cls, Some(vm.ctx.type_type()))]);
65-
match _mro(cls.clone()) {
66-
Some(mro) => Ok(vm.context().new_tuple(mro)),
67-
None => Err(vm.new_type_error("Only classes have an MRO.".to_string())),
68-
}
100+
fn type_mro(cls: PyClassRef, _vm: &mut VirtualMachine) -> PyResult<PyTuple> {
101+
Ok(PyTuple::from(_mro(&cls)))
69102
}
70103

71-
fn _mro(cls: PyObjectRef) -> Option<Vec<PyObjectRef>> {
72-
if let Some(PyClass { ref mro, .. }) = cls.payload::<PyClass>() {
73-
let mut mro = mro.clone();
74-
mro.insert(0, cls.clone());
75-
Some(mro)
76-
} else {
77-
None
78-
}
104+
fn _mro(cls: &PyClassRef) -> Vec<PyObjectRef> {
105+
cls.iter_mro().cloned().collect()
79106
}
80107

81108
/// Determines if `obj` actually an instance of `cls`, this doesn't call __instancecheck__, so only
@@ -212,24 +239,22 @@ pub fn type_getattribute(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult
212239
}
213240
}
214241

215-
pub fn type_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
216-
arg_check!(vm, args, required = [(obj, None)]);
217-
218-
let attributes = get_attributes(&obj);
219-
Ok(vm.ctx.new_list(
220-
attributes
221-
.keys()
222-
.map(|k| vm.ctx.new_str(k.to_string()))
223-
.collect(),
224-
))
242+
pub fn type_dir(obj: PyClassRef, vm: &mut VirtualMachine) -> PyList {
243+
let attributes = get_attributes(obj);
244+
let attributes: Vec<PyObjectRef> = attributes
245+
.keys()
246+
.map(|k| vm.ctx.new_str(k.to_string()))
247+
.collect();
248+
PyList::from(attributes)
225249
}
226250

227-
pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes {
251+
pub fn get_attributes(cls: PyClassRef) -> PyAttributes {
228252
// Gather all members here:
229253
let mut attributes = PyAttributes::new();
230254

231-
let mut base_classes = _mro(obj.clone()).expect("Type get_attributes on non-type");
255+
let mut base_classes: Vec<&PyObjectRef> = cls.iter_mro().collect();
232256
base_classes.reverse();
257+
233258
for bc in base_classes {
234259
if let Some(ref dict) = &bc.dict {
235260
for (name, value) in dict.borrow().iter() {
@@ -294,7 +319,10 @@ pub fn new(
294319
bases: Vec<PyObjectRef>,
295320
dict: HashMap<String, PyObjectRef>,
296321
) -> PyResult {
297-
let mros = bases.into_iter().map(|x| _mro(x).unwrap()).collect();
322+
let mros = bases
323+
.into_iter()
324+
.map(|x| _mro(&FromPyObjectRef::from_pyobj(&x)))
325+
.collect();
298326
let mro = linearise_mro(mros).unwrap();
299327
Ok(PyObject {
300328
payload: Box::new(PyClass {

0 commit comments

Comments
 (0)