@@ -340,6 +340,30 @@ pub unsafe extern "C" fn get_from_string_map(
340
340
. and_then ( |v| allocate_fn ( kernel_string_slice ! ( v) ) )
341
341
}
342
342
343
+ /// Visit all values in a CStringMap. The callback will be called once for each element of the map
344
+ ///
345
+ /// # Safety
346
+ ///
347
+ /// The engine is responsible for providing a valid [`CStringMap`] pointer and callback
348
+ #[ no_mangle]
349
+ pub unsafe extern "C" fn visit_string_map (
350
+ map : & CStringMap ,
351
+ engine_context : NullableCvoid ,
352
+ visitor : extern "C" fn (
353
+ engine_context : NullableCvoid ,
354
+ key : KernelStringSlice ,
355
+ value : KernelStringSlice ,
356
+ ) ,
357
+ ) {
358
+ for ( key, val) in map. values . iter ( ) {
359
+ visitor (
360
+ engine_context,
361
+ kernel_string_slice ! ( key) ,
362
+ kernel_string_slice ! ( val) ,
363
+ ) ;
364
+ }
365
+ }
366
+
343
367
/// Transformation expressions that need to be applied to each row `i` in ScanMetadata. You can use
344
368
/// [`get_transform_for_row`] to get the transform for a particular row. If that returns an
345
369
/// associated expression, it _must_ be applied to the data read from the file specified by the
@@ -487,3 +511,42 @@ pub unsafe extern "C" fn visit_scan_metadata(
487
511
. visit_scan_files ( context_wrapper, rust_callback)
488
512
. unwrap ( ) ;
489
513
}
514
+
515
+ #[ cfg( test) ]
516
+ mod tests {
517
+ use std:: { collections:: HashMap , ptr:: NonNull } ;
518
+
519
+ use crate :: { KernelStringSlice , NullableCvoid , TryFromStringSlice } ;
520
+
521
+ extern "C" fn visit_entry (
522
+ engine_context : NullableCvoid ,
523
+ key : KernelStringSlice ,
524
+ value : KernelStringSlice ,
525
+ ) {
526
+ let map_ptr: * mut HashMap < String , String > = engine_context. unwrap ( ) . as_ptr ( ) . cast ( ) ;
527
+ let key = unsafe { String :: try_from_slice ( & key) . unwrap ( ) } ;
528
+ let value = unsafe { String :: try_from_slice ( & value) . unwrap ( ) } ;
529
+ unsafe {
530
+ ( * map_ptr) . insert ( key, value) ;
531
+ }
532
+ }
533
+
534
+ #[ test]
535
+ fn visit_string_map ( ) {
536
+ let test_map: HashMap < String , String > = HashMap :: from ( [
537
+ ( "A" . into ( ) , "B" . into ( ) ) ,
538
+ ( "C" . into ( ) , "D" . into ( ) ) ,
539
+ ( "E" . into ( ) , "F" . into ( ) ) ,
540
+ ( "G" . into ( ) , "H" . into ( ) ) ,
541
+ ] ) ;
542
+ let cmap: super :: CStringMap = test_map. clone ( ) . into ( ) ;
543
+ let context_map: Box < HashMap < String , String > > = Box :: default ( ) ;
544
+ let map_ptr: * mut HashMap < String , String > = Box :: into_raw ( context_map) ;
545
+ unsafe {
546
+ let ptr = NonNull :: new_unchecked ( map_ptr. cast ( ) ) ;
547
+ super :: visit_string_map ( & cmap, Some ( ptr) , visit_entry) ;
548
+ }
549
+ let final_map: HashMap < String , String > = * unsafe { Box :: from_raw ( map_ptr) } ;
550
+ assert_eq ! ( test_map, final_map) ;
551
+ }
552
+ }
0 commit comments