@@ -4,6 +4,7 @@ use crate::pystate::with_vm;
44use core:: ffi:: c_int;
55use core:: ptr:: NonNull ;
66use rustpython_vm:: AsObject ;
7+ use rustpython_vm:: PyPayload ;
78use rustpython_vm:: builtins:: PyDict ;
89
910define_py_check ! ( fn PyDict_Check , types. dict_type) ;
@@ -64,6 +65,100 @@ pub unsafe extern "C" fn PyDict_Size(dict: *mut PyObject) -> isize {
6465 } )
6566}
6667
68+ #[ unsafe( no_mangle) ]
69+ pub unsafe extern "C" fn PyDict_Contains ( dict : * mut PyObject , key : * mut PyObject ) -> c_int {
70+ with_vm ( |vm| {
71+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
72+ let key = unsafe { & * key } ;
73+ Ok ( dict. inner_getitem_opt ( key, vm) ?. is_some ( ) )
74+ } )
75+ }
76+
77+ #[ unsafe( no_mangle) ]
78+ pub unsafe extern "C" fn PyDict_Copy ( dict : * mut PyObject ) -> * mut PyObject {
79+ with_vm ( |vm| {
80+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
81+ Ok ( dict. copy ( ) . into_ref ( & vm. ctx ) )
82+ } )
83+ }
84+
85+ #[ unsafe( no_mangle) ]
86+ pub unsafe extern "C" fn PyDict_DelItem ( dict : * mut PyObject , key : * mut PyObject ) -> c_int {
87+ with_vm ( |vm| {
88+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
89+ let key = unsafe { & * key } ;
90+ dict. del_item ( key, vm)
91+ } )
92+ }
93+
94+ #[ unsafe( no_mangle) ]
95+ pub unsafe extern "C" fn PyDict_Items ( dict : * mut PyObject ) -> * mut PyObject {
96+ with_vm ( |vm| {
97+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
98+ let items = dict
99+ . items_vec ( )
100+ . into_iter ( )
101+ . map ( |( k, v) | vm. ctx . new_tuple ( vec ! [ k, v] ) . into ( ) )
102+ . collect ( ) ;
103+ Ok ( vm. ctx . new_list ( items) )
104+ } )
105+ }
106+
107+ #[ unsafe( no_mangle) ]
108+ pub unsafe extern "C" fn PyDict_Keys ( dict : * mut PyObject ) -> * mut PyObject {
109+ with_vm ( |vm| {
110+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
111+ Ok ( vm. ctx . new_list ( dict. keys_vec ( ) ) )
112+ } )
113+ }
114+
115+ #[ unsafe( no_mangle) ]
116+ pub unsafe extern "C" fn PyDict_Values ( dict : * mut PyObject ) -> * mut PyObject {
117+ with_vm ( |vm| {
118+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
119+ Ok ( vm. ctx . new_list ( dict. values_vec ( ) ) )
120+ } )
121+ }
122+
123+ #[ unsafe( no_mangle) ]
124+ pub unsafe extern "C" fn PyDict_Merge (
125+ dict : * mut PyObject ,
126+ other : * mut PyObject ,
127+ override_ : c_int ,
128+ ) -> c_int {
129+ with_vm ( |vm| {
130+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
131+ let other = unsafe { & * other } . to_owned ( ) ;
132+ if override_ != 0 {
133+ dict. merge_object ( other, vm)
134+ } else {
135+ dict. merge_object_if_missing ( other, vm)
136+ }
137+ } )
138+ }
139+
140+ #[ unsafe( no_mangle) ]
141+ pub unsafe extern "C" fn PyDict_Update ( dict : * mut PyObject , other : * mut PyObject ) -> c_int {
142+ with_vm ( |vm| {
143+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
144+ let other = unsafe { & * other } . to_owned ( ) ;
145+ dict. merge_object ( other, vm)
146+ } )
147+ }
148+
149+ #[ unsafe( no_mangle) ]
150+ pub unsafe extern "C" fn PyDict_MergeFromSeq2 (
151+ dict : * mut PyObject ,
152+ seq2 : * mut PyObject ,
153+ override_ : c_int ,
154+ ) -> c_int {
155+ with_vm ( |vm| {
156+ let dict = unsafe { & * dict } . try_downcast_ref :: < PyDict > ( vm) ?;
157+ let seq2 = unsafe { & * seq2 } . to_owned ( ) ;
158+ dict. merge_from_seq2 ( seq2, override_ != 0 , vm)
159+ } )
160+ }
161+
67162#[ unsafe( no_mangle) ]
68163pub unsafe extern "C" fn PyDict_Next (
69164 dict : * mut PyObject ,
@@ -95,7 +190,7 @@ pub unsafe extern "C" fn PyDict_Next(
95190#[ cfg( false ) ]
96191mod tests {
97192 use pyo3:: prelude:: * ;
98- use pyo3:: types:: { IntoPyDict , PyDict , PyInt } ;
193+ use pyo3:: types:: { IntoPyDict , PyDict , PyDictMethods , PyInt , PyList } ;
99194
100195 #[ test]
101196 fn test_create_empty_dict ( ) {
@@ -129,4 +224,78 @@ mod tests {
129224 assert_eq ! ( values, vec![ 1 , 2 , 3 , 4 ] ) ;
130225 } )
131226 }
227+
228+ #[ test]
229+ fn dict_contains ( ) {
230+ Python :: attach ( |py| {
231+ let dict = [ ( 1 , 2 ) ] . into_py_dict ( py) . unwrap ( ) ;
232+ assert ! ( dict. contains( 1 ) . unwrap( ) ) ;
233+ assert ! ( !dict. contains( 3 ) . unwrap( ) ) ;
234+ } )
235+ }
236+
237+ #[ test]
238+ fn dict_copy_and_del_item ( ) {
239+ Python :: attach ( |py| {
240+ let dict = [ ( 1 , 2 ) , ( 3 , 4 ) ] . into_py_dict ( py) . unwrap ( ) ;
241+ let copied = dict. copy ( ) . unwrap ( ) ;
242+ assert_eq ! ( copied. len( ) , 2 ) ;
243+ copied. del_item ( 1 ) . unwrap ( ) ;
244+ assert ! ( !copied. contains( 1 ) . unwrap( ) ) ;
245+ } )
246+ }
247+
248+ #[ test]
249+ fn dict_keys_values_items ( ) {
250+ Python :: attach ( |py| {
251+ let dict = [ ( 1 , 2 ) , ( 3 , 4 ) ] . into_py_dict ( py) . unwrap ( ) ;
252+ assert_eq ! ( dict. keys( ) . len( ) , 2 ) ;
253+ assert_eq ! ( dict. values( ) . len( ) , 2 ) ;
254+ assert_eq ! ( dict. items( ) . len( ) , 2 ) ;
255+ } )
256+ }
257+
258+ #[ test]
259+ fn dict_update_and_merge ( ) {
260+ Python :: attach ( |py| {
261+ let dict = [ ( 1 , 10 ) ] . into_py_dict ( py) . unwrap ( ) ;
262+ let replacement = [ ( 1 , 20 ) , ( 2 , 30 ) ] . into_py_dict ( py) . unwrap ( ) ;
263+ dict. update ( replacement. as_mapping ( ) ) . unwrap ( ) ;
264+ assert_eq ! (
265+ dict. get_item( 1 ) . unwrap( ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ,
266+ 20
267+ ) ;
268+ assert_eq ! (
269+ dict. get_item( 2 ) . unwrap( ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ,
270+ 30
271+ ) ;
272+
273+ let merged_missing = [ ( 1 , 99 ) , ( 3 , 40 ) ] . into_py_dict ( py) . unwrap ( ) ;
274+ dict. update_if_missing ( merged_missing. as_mapping ( ) ) . unwrap ( ) ;
275+ assert_eq ! (
276+ dict. get_item( 1 ) . unwrap( ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ,
277+ 20
278+ ) ;
279+ assert_eq ! (
280+ dict. get_item( 3 ) . unwrap( ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ,
281+ 40
282+ ) ;
283+ } )
284+ }
285+
286+ #[ test]
287+ fn dict_merge_from_seq2 ( ) {
288+ Python :: attach ( |py| {
289+ let seq = PyList :: new ( py, [ ( 1 , 10 ) , ( 1 , 20 ) , ( 2 , 30 ) ] ) . unwrap ( ) ;
290+ let dict = PyDict :: from_sequence ( seq. as_any ( ) ) . unwrap ( ) ;
291+ assert_eq ! (
292+ dict. get_item( 1 ) . unwrap( ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ,
293+ 20
294+ ) ;
295+ assert_eq ! (
296+ dict. get_item( 2 ) . unwrap( ) . unwrap( ) . extract:: <i32 >( ) . unwrap( ) ,
297+ 30
298+ ) ;
299+ } )
300+ }
132301}
0 commit comments