diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index b4d3a3f0f..565867a34 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -167,6 +167,14 @@ impl PyListRef { fn reverse(self, _vm: &VirtualMachine) { self.elements.borrow_mut().reverse(); } + + fn reversed(self, _vm: &VirtualMachine) -> PyListReverseIterator { + let final_position = self.elements.borrow().len(); + PyListReverseIterator { + position: Cell::new(final_position), + list: self, + } + } fn getitem(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { get_item( @@ -397,7 +405,7 @@ impl PyListRef { .collect(); vm.ctx.new_list(new_elements) } - + fn imul(self, counter: isize, _vm: &VirtualMachine) -> Self { let new_elements = seq_mul(&self.elements.borrow().as_slice(), counter) .cloned() @@ -405,7 +413,7 @@ impl PyListRef { self.elements.replace(new_elements); self } - + fn count(self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { let mut count: usize = 0; for element in self.elements.borrow().iter() { @@ -813,6 +821,39 @@ impl PyListIterator { } } +#[pyclass] +#[derive(Debug)] +pub struct PyListReverseIterator { + pub position: Cell, + pub list: PyListRef, +} + +impl PyValue for PyListReverseIterator { + fn class(vm: &VirtualMachine) -> PyClassRef { + vm.ctx.listreverseiterator_type() + } +} + +#[pyimpl] +impl PyListReverseIterator { + #[pymethod(name = "__next__")] + fn next(&self, vm: &VirtualMachine) -> PyResult { + if self.position.get() > 0 { + let position: usize = self.position.get() - 1; + let ret = self.list.elements.borrow()[position].clone(); + self.position.set(position); + Ok(ret) + } else { + Err(objiter::new_stop_iteration(vm)) + } + } + + #[pymethod(name = "__iter__")] + fn iter(zelf: PyRef, _vm: &VirtualMachine) -> PyRef { + zelf + } +} + #[rustfmt::skip] // to avoid line splitting pub fn init(context: &PyContext) { let list_type = &context.list_type; @@ -835,6 +876,7 @@ pub fn init(context: &PyContext) { "__getitem__" => context.new_rustfunc(PyListRef::getitem), "__iter__" => context.new_rustfunc(PyListRef::iter), "__setitem__" => context.new_rustfunc(PyListRef::setitem), + "__reversed__" => context.new_rustfunc(PyListRef::reversed), "__mul__" => context.new_rustfunc(PyListRef::mul), "__imul__" => context.new_rustfunc(PyListRef::imul), "__len__" => context.new_rustfunc(PyListRef::len), @@ -856,4 +898,5 @@ pub fn init(context: &PyContext) { }); PyListIterator::extend_class(context, &context.listiterator_type); + PyListReverseIterator::extend_class(context, &context.listreverseiterator_type); } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index ffb471f99..ad8546afb 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -134,6 +134,7 @@ pub struct PyContext { pub false_value: PyIntRef, pub list_type: PyClassRef, pub listiterator_type: PyClassRef, + pub listreverseiterator_type: PyClassRef, pub dictkeyiterator_type: PyClassRef, pub dictvalueiterator_type: PyClassRef, pub dictitemiterator_type: PyClassRef, @@ -271,6 +272,7 @@ impl PyContext { let str_type = create_type("str", &type_type, &object_type); let list_type = create_type("list", &type_type, &object_type); let listiterator_type = create_type("list_iterator", &type_type, &object_type); + let listreverseiterator_type = create_type("list_reverseiterator", &type_type, &object_type); let dictkeys_type = create_type("dict_keys", &type_type, &object_type); let dictvalues_type = create_type("dict_values", &type_type, &object_type); let dictitems_type = create_type("dict_items", &type_type, &object_type); @@ -337,6 +339,7 @@ impl PyContext { staticmethod_type, list_type, listiterator_type, + listreverseiterator_type, dictkeys_type, dictvalues_type, dictitems_type, @@ -467,6 +470,10 @@ impl PyContext { pub fn listiterator_type(&self) -> PyClassRef { self.listiterator_type.clone() } + + pub fn listreverseiterator_type(&self) -> PyClassRef { + self.listreverseiterator_type.clone() + } pub fn module_type(&self) -> PyClassRef { self.module_type.clone()