From 03ed6cfc88453905b8ef4fe210aaba796eec3cbb Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Mon, 13 Jul 2026 14:51:23 +0200 Subject: [PATCH 1/2] Add more dict functions to c-api --- crates/capi/src/dictobject.rs | 115 +++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/crates/capi/src/dictobject.rs b/crates/capi/src/dictobject.rs index e326ba87e3a..3eb9113df15 100644 --- a/crates/capi/src/dictobject.rs +++ b/crates/capi/src/dictobject.rs @@ -1,7 +1,7 @@ use crate::PyObject; use crate::object::define_py_check; use crate::pystate::with_vm; -use core::ffi::c_int; +use core::ffi::{CStr, c_char, c_int}; use core::ptr::NonNull; use rustpython_vm::AsObject; use rustpython_vm::PyPayload; @@ -18,6 +18,15 @@ pub extern "C" fn PyDict_New() -> *mut PyObject { with_vm(|vm| vm.ctx.new_dict()) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDict_Clear(dict: *mut PyObject) { + with_vm(|vm| { + let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + dict.clear(); + Ok(()) + }) +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_SetItem( dict: *mut PyObject, @@ -32,6 +41,99 @@ pub unsafe extern "C" fn PyDict_SetItem( }) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDict_SetItemString( + dict: *mut PyObject, + key: *const c_char, + val: *mut PyObject, +) -> c_int { + with_vm(|vm| { + let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let key = unsafe { CStr::from_ptr(key) } + .to_str() + .map_err(|_| vm.new_value_error("dictionary key must be valid UTF-8"))?; + let value = unsafe { &*val }.to_owned(); + dict.inner_setitem(key, value, vm) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDict_GetItem(dict: *mut PyObject, key: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let key = unsafe { &*key }; + + match dict.inner_getitem_opt(key, vm) { + Ok(Some(value)) => Ok(value.as_object().as_raw().cast_mut()), + Ok(None) | Err(_) => Ok(core::ptr::null_mut()), + } + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDict_GetItemWithError( + dict: *mut PyObject, + key: *mut PyObject, +) -> *mut PyObject { + with_vm(|vm| { + let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let key = unsafe { &*key }; + + if let Some(value) = dict.inner_getitem_opt(key, vm)? { + Ok(value.as_object().as_raw().cast_mut()) + } else { + Ok(core::ptr::null_mut()) + } + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDict_GetItemString( + dict: *mut PyObject, + key: *const c_char, +) -> *mut PyObject { + with_vm(|vm| { + let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let key = match unsafe { CStr::from_ptr(key) }.to_str() { + Ok(key) => key, + Err(_) => { + return Ok(core::ptr::null_mut()); + } + }; + + match dict.inner_getitem_opt(key, vm) { + Ok(Some(value)) => Ok(value.as_object().as_raw().cast_mut()), + Ok(None) | Err(_) => Ok(core::ptr::null_mut()), + } + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDict_GetItemStringRef( + dict: *mut PyObject, + key: *const c_char, + result: *mut *mut PyObject, +) -> c_int { + with_vm(|vm| { + unsafe { + *result = core::ptr::null_mut(); + } + let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let key = unsafe { CStr::from_ptr(key) } + .to_str() + .map_err(|_| vm.new_value_error("dictionary key must be valid UTF-8"))?; + + if let Some(value) = dict.inner_getitem_opt(key, vm)? { + unsafe { + *result = value.into_raw().as_ptr(); + } + Ok(true) + } else { + Ok(false) + } + }) +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_GetItemRef( dict: *mut PyObject, @@ -128,6 +230,17 @@ pub unsafe extern "C" fn PyDict_DelItem(dict: *mut PyObject, key: *mut PyObject) }) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDict_DelItemString(dict: *mut PyObject, key: *const c_char) -> c_int { + with_vm(|vm| { + let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; + let key = unsafe { CStr::from_ptr(key) } + .to_str() + .map_err(|_| vm.new_value_error("dictionary key must be valid UTF-8"))?; + dict.del_item(key, vm) + }) +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDict_Items(dict: *mut PyObject) -> *mut PyObject { with_vm(|vm| { From 3db587791a7b258ff69a68b548ed1043f3ce3cd3 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Mon, 13 Jul 2026 15:06:35 +0200 Subject: [PATCH 2/2] Review --- crates/capi/src/dictobject.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/capi/src/dictobject.rs b/crates/capi/src/dictobject.rs index 3eb9113df15..6cea9ea343c 100644 --- a/crates/capi/src/dictobject.rs +++ b/crates/capi/src/dictobject.rs @@ -94,16 +94,13 @@ pub unsafe extern "C" fn PyDict_GetItemString( ) -> *mut PyObject { with_vm(|vm| { let dict = unsafe { &*dict }.try_downcast_ref::(vm)?; - let key = match unsafe { CStr::from_ptr(key) }.to_str() { - Ok(key) => key, - Err(_) => { - return Ok(core::ptr::null_mut()); - } - }; + let key = unsafe { CStr::from_ptr(key) } + .to_str() + .map_err(|_| vm.new_unicode_decode_error("dictionary key must be valid UTF-8"))?; - match dict.inner_getitem_opt(key, vm) { - Ok(Some(value)) => Ok(value.as_object().as_raw().cast_mut()), - Ok(None) | Err(_) => Ok(core::ptr::null_mut()), + match dict.inner_getitem_opt(key, vm)? { + Some(value) => Ok(value.as_object().as_raw().cast_mut()), + None => Ok(core::ptr::null_mut()), } }) }