Skip to content

Commit 1ddc026

Browse files
authored
feat: Add visit_string_map to the ffi (#1342)
1 parent af6a5f5 commit 1ddc026

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

ffi/src/scan.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,30 @@ pub unsafe extern "C" fn get_from_string_map(
340340
.and_then(|v| allocate_fn(kernel_string_slice!(v)))
341341
}
342342

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+
343367
/// Transformation expressions that need to be applied to each row `i` in ScanMetadata. You can use
344368
/// [`get_transform_for_row`] to get the transform for a particular row. If that returns an
345369
/// 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(
487511
.visit_scan_files(context_wrapper, rust_callback)
488512
.unwrap();
489513
}
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

Comments
 (0)