◐ Shell
reader mode source ↗
Skip to content
Merged
Changes from all commits
File filter
Conversations
Jump to
Diff view
Apply and reload
Show whitespace
Diff view
Apply and reload
171 changes: 170 additions & 1 deletion crates/capi/src/dictobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::pystate::with_vm;
use core::ffi::c_int;
use core::ptr::NonNull;
use rustpython_vm::AsObject;
use rustpython_vm::builtins::PyDict;

define_py_check!(fn PyDict_Check, types.dict_type);
Expand Down Expand Up @@ -64,6 +65,100 @@ pub unsafe extern "C" fn PyDict_Size(dict: *mut PyObject) -> isize {
})
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn PyDict_Next(
dict: *mut PyObject,
Expand Down Expand Up @@ -95,7 +190,7 @@ pub unsafe extern "C" fn PyDict_Next(
#[cfg(false)]
mod tests {
use pyo3::prelude::*;
use pyo3::types::{IntoPyDict, PyDict, PyInt};

#[test]
fn test_create_empty_dict() {
Expand Down Expand Up @@ -129,4 +224,78 @@ mod tests {
assert_eq!(values, vec![1, 2, 3, 4]);
})
}
}
84 changes: 62 additions & 22 deletions crates/vm/src/builtins/dict.rs
Original file line number Diff line number Diff line change
@@ -143,11 +143,17 @@ impl PyDict {
self.entries.items()
}

// Used in update and ior.
pub(crate) fn merge_object(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let casted: Result<PyRefExact<Self>, _> = other.downcast_exact(vm);
let other = match casted {
Ok(dict_other) => return self.merge_dict(dict_other.into_pyref(), vm),
Err(other) => other,
};
let dict = &self.entries;
Expand All @@ -157,6 +163,9 @@ impl PyDict {
Ok(keys_method) => {
let keys = keys_method.call((), vm)?.get_iter(vm)?;
while let PyIterReturn::Return(key) = keys.next(vm)? {
let val = other.get_item(&*key, vm)?;
dict.insert(vm, &*key, val)?;
}
Expand All @@ -166,31 +175,62 @@ impl PyDict {
Err(e) => return Err(e),
};
if !has_keys {
let iter = other.get_iter(vm)?;
loop {
fn err(vm: &VirtualMachine) -> PyBaseExceptionRef {
vm.new_value_error("Iterator must have exactly two elements")
}
let element = match iter.next(vm)? {
PyIterReturn::Return(obj) => obj,
PyIterReturn::StopIteration(_) => break,
};
let elem_iter = element.get_iter(vm)?;
let key = elem_iter.next(vm)?.into_result().map_err(|_| err(vm))?;
let value = elem_iter.next(vm)?.into_result().map_err(|_| err(vm))?;
if matches!(elem_iter.next(vm)?, PyIterReturn::Return(_)) {
return Err(err(vm));
}
dict.insert(vm, &*key, value)?;
}
}
Ok(())
}

fn merge_dict(&self, dict_other: PyDictRef, vm: &VirtualMachine) -> PyResult<()> {
let dict = &self.entries;
let dict_size = &dict_other.size();
for (key, value) in &dict_other {
dict.insert(vm, &*key, value)?;
}
if dict_other.entries.has_changed_size(dict_size) {
Expand Down Expand Up @@ -386,7 +426,7 @@ impl PyDict {
let other_dict: Result<PyDictRef, _> = other.downcast();
if let Ok(other) = other_dict {
let self_cp = self.copy();
self_cp.merge_dict(other, vm)?;
return Ok(self_cp.into_pyobject(vm));
}
Ok(vm.ctx.not_implemented())
Expand Down Expand Up @@ -499,7 +539,7 @@ impl PyRef<PyDict> {
let other_dict: Result<Self, _> = other.downcast();
if let Ok(other) = other_dict {
let other_cp = other.copy();
other_cp.merge_dict(self, vm)?;
return Ok(other_cp.into_pyobject(vm));
}
Ok(vm.ctx.not_implemented())
Expand Down
Loading
Toggle all file notes Toggle all file annotations