use ahash::AHashSet;
#[no_mangle]
pub extern "C" fn ragc_is_splitter(
kmer_value: u64,
splitters_ptr: *const u64,
splitters_len: usize,
) -> bool {
unsafe {
let splitters = std::slice::from_raw_parts(splitters_ptr, splitters_len);
splitters.binary_search(&kmer_value).is_ok()
}
}
#[repr(C)]
pub struct SplitterChecker {
pub splitters: *mut u64,
pub len: usize,
}
#[no_mangle]
pub extern "C" fn ragc_create_splitter_checker(
splitters_ptr: *const u64,
splitters_len: usize,
) -> SplitterChecker {
unsafe {
let splitters_slice = std::slice::from_raw_parts(splitters_ptr, splitters_len);
let mut splitters_vec: Vec<u64> = splitters_slice.to_vec();
splitters_vec.sort_unstable();
let ptr = splitters_vec.as_mut_ptr();
let len = splitters_vec.len();
std::mem::forget(splitters_vec);
SplitterChecker {
splitters: ptr,
len,
}
}
}
#[no_mangle]
pub extern "C" fn ragc_free_splitter_checker(checker: SplitterChecker) {
unsafe {
if !checker.splitters.is_null() && checker.len > 0 {
let _ = Vec::from_raw_parts(checker.splitters, checker.len, checker.len);
}
}
}
#[repr(C)]
pub struct BoolArray {
pub data: *mut bool,
pub len: usize,
}
#[no_mangle]
pub extern "C" fn ragc_check_splitters_batch(
kmers_ptr: *const u64,
kmers_len: usize,
splitters_ptr: *const u64,
splitters_len: usize,
) -> BoolArray {
unsafe {
let kmers = std::slice::from_raw_parts(kmers_ptr, kmers_len);
let splitters_slice = std::slice::from_raw_parts(splitters_ptr, splitters_len);
let splitter_set: AHashSet<u64> = splitters_slice.iter().copied().collect();
let mut results: Vec<bool> = kmers
.iter()
.map(|kmer| splitter_set.contains(kmer))
.collect();
let ptr = results.as_mut_ptr();
let len = results.len();
std::mem::forget(results);
BoolArray { data: ptr, len }
}
}
#[no_mangle]
pub extern "C" fn ragc_free_bool_array(array: BoolArray) {
unsafe {
if !array.data.is_null() && array.len > 0 {
let _ = Vec::from_raw_parts(array.data, array.len, array.len);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_splitter() {
let splitters = vec![100u64, 200, 300, 400, 500];
assert!(ragc_is_splitter(300, splitters.as_ptr(), splitters.len()));
assert!(!ragc_is_splitter(350, splitters.as_ptr(), splitters.len()));
assert!(ragc_is_splitter(100, splitters.as_ptr(), splitters.len()));
assert!(ragc_is_splitter(500, splitters.as_ptr(), splitters.len()));
}
#[test]
fn test_splitter_checker() {
let splitters = vec![300u64, 100, 500, 200, 400]; let checker = ragc_create_splitter_checker(splitters.as_ptr(), splitters.len());
unsafe {
let sorted = std::slice::from_raw_parts(checker.splitters, checker.len);
assert_eq!(sorted, &[100, 200, 300, 400, 500]);
}
ragc_free_splitter_checker(checker);
}
#[test]
fn test_batch_check() {
let splitters = vec![100u64, 200, 300];
let kmers = vec![50u64, 100, 150, 200, 250, 300, 350];
let results = ragc_check_splitters_batch(
kmers.as_ptr(),
kmers.len(),
splitters.as_ptr(),
splitters.len(),
);
unsafe {
let checks = std::slice::from_raw_parts(results.data, results.len);
assert_eq!(checks, &[false, true, false, true, false, true, false]);
}
ragc_free_bool_array(results);
}
}