@@ -3,8 +3,7 @@ use std::fmt;
33
44use crate :: function:: { KwArgs , OptionalArg } ;
55use crate :: pyobject:: {
6- IdProtocol , IntoPyObject , ItemProtocol , PyAttributes , PyContext , PyObjectRef , PyRef , PyResult ,
7- PyValue ,
6+ IntoPyObject , ItemProtocol , PyAttributes , PyContext , PyObjectRef , PyRef , PyResult , PyValue ,
87} ;
98use crate :: vm:: { ReprGuard , VirtualMachine } ;
109
@@ -63,9 +62,8 @@ impl PyDictRef {
6362 if let OptionalArg :: Present ( dict_obj) = dict_obj {
6463 let dicted: PyResult < PyDictRef > = dict_obj. clone ( ) . downcast ( ) ;
6564 if let Ok ( dict_obj) = dicted {
66- let mut dict_borrowed = dict. borrow_mut ( ) ;
67- for ( key, value) in dict_obj. entries . borrow ( ) . iter_items ( ) {
68- dict_borrowed. insert ( vm, & key, value) ?;
65+ for ( key, value) in dict_obj {
66+ dict. borrow_mut ( ) . insert ( vm, & key, value) ?;
6967 }
7068 } else {
7169 let iter = objiter:: get_iter ( vm, & dict_obj) ?;
@@ -105,7 +103,7 @@ impl PyDictRef {
105103 fn repr ( self , vm : & VirtualMachine ) -> PyResult < String > {
106104 let s = if let Some ( _guard) = ReprGuard :: enter ( self . as_object ( ) ) {
107105 let mut str_parts = vec ! [ ] ;
108- for ( key, value) in self . get_key_value_pairs ( ) {
106+ for ( key, value) in self {
109107 let key_repr = vm. to_repr ( & key) ?;
110108 let value_repr = vm. to_repr ( & value) ?;
111109 str_parts. push ( format ! ( "{}: {}" , key_repr. value, value_repr. value) ) ;
@@ -146,10 +144,6 @@ impl PyDictRef {
146144 PyDictItems :: new ( self )
147145 }
148146
149- pub fn get_key_value_pairs ( & self ) -> Vec < ( PyObjectRef , PyObjectRef ) > {
150- self . entries . borrow ( ) . get_items ( )
151- }
152-
153147 fn inner_setitem (
154148 self ,
155149 key : PyObjectRef ,
@@ -194,24 +188,17 @@ impl PyDictRef {
194188
195189 fn update (
196190 self ,
197- mut dict_obj : OptionalArg < PyObjectRef > ,
191+ dict_obj : OptionalArg < PyObjectRef > ,
198192 kwargs : KwArgs ,
199193 vm : & VirtualMachine ,
200194 ) -> PyResult < ( ) > {
201- if let OptionalArg :: Present ( ref other) = dict_obj {
202- if self . is ( other) {
203- // Updating yourself is a noop, and this avoids a borrow error
204- dict_obj = OptionalArg :: Missing ;
205- }
206- }
207-
208195 PyDictRef :: merge ( & self . entries , dict_obj, kwargs, vm)
209196 }
210197
211198 /// Take a python dictionary and convert it to attributes.
212199 pub fn to_attributes ( self ) -> PyAttributes {
213200 let mut attrs = PyAttributes :: new ( ) ;
214- for ( key, value) in self . get_key_value_pairs ( ) {
201+ for ( key, value) in self {
215202 let key = objstr:: get_value ( & key) ;
216203 attrs. insert ( key, value) ;
217204 }
@@ -247,6 +234,50 @@ impl ItemProtocol for PyDictRef {
247234 }
248235}
249236
237+ // Implement IntoIterator so that we can easily iterate dictionaries from rust code.
238+ impl IntoIterator for PyDictRef {
239+ type Item = ( PyObjectRef , PyObjectRef ) ;
240+ type IntoIter = DictIter ;
241+
242+ fn into_iter ( self ) -> Self :: IntoIter {
243+ DictIter :: new ( self )
244+ }
245+ }
246+
247+ impl IntoIterator for & PyDictRef {
248+ type Item = ( PyObjectRef , PyObjectRef ) ;
249+ type IntoIter = DictIter ;
250+
251+ fn into_iter ( self ) -> Self :: IntoIter {
252+ DictIter :: new ( self . clone ( ) )
253+ }
254+ }
255+
256+ pub struct DictIter {
257+ dict : PyDictRef ,
258+ position : usize ,
259+ }
260+
261+ impl DictIter {
262+ pub fn new ( dict : PyDictRef ) -> DictIter {
263+ DictIter { dict, position : 0 }
264+ }
265+ }
266+
267+ impl Iterator for DictIter {
268+ type Item = ( PyObjectRef , PyObjectRef ) ;
269+
270+ fn next ( & mut self ) -> Option < Self :: Item > {
271+ match self . dict . entries . borrow ( ) . next_entry ( self . position ) {
272+ Some ( ( new_position, key, value) ) => {
273+ self . position = new_position;
274+ Some ( ( key. clone ( ) , value. clone ( ) ) )
275+ }
276+ None => None ,
277+ }
278+ }
279+ }
280+
250281macro_rules! dict_iterator {
251282 ( $name: ident, $iter_name: ident, $class: ident, $iter_class: ident, $class_name: literal, $iter_class_name: literal, $result_fn: expr) => {
252283 #[ pyclass( name = $class_name, __inside_vm) ]
0 commit comments