use crate::kmer::{Kmer, KmerMode};
use crate::kmer_extract::{
find_new_splitters_kmers, remove_non_singletons, remove_non_singletons_with_duplicates,
};
use std::slice;
#[repr(C)]
pub struct KmerArray {
pub data: *mut u64,
pub len: usize,
}
#[no_mangle]
pub extern "C" fn ragc_extract_canonical_kmers(
contig_data: *const u8,
contig_len: usize,
k: u32,
) -> KmerArray {
unsafe {
let contig = slice::from_raw_parts(contig_data, contig_len);
let mut kmers = Vec::new();
let mut kmer = Kmer::new(k, KmerMode::Canonical);
for &base in contig {
if base > 3 {
kmer.reset();
} else {
kmer.insert(base as u64);
if kmer.is_full() {
kmers.push(kmer.data());
}
}
}
let mut result = kmers;
let result_ptr = result.as_mut_ptr();
let result_len = result.len();
std::mem::forget(result);
KmerArray {
data: result_ptr,
len: result_len,
}
}
}
#[no_mangle]
pub extern "C" fn ragc_free_kmer_array(array: KmerArray) {
unsafe {
if !array.data.is_null() && array.len > 0 {
let _ = Vec::from_raw_parts(array.data, array.len, array.len);
}
}
}
#[no_mangle]
pub extern "C" fn ragc_extract_kmer_at_position(
contig_data: *const u8,
contig_len: usize,
k: u32,
pos: usize,
) -> u64 {
unsafe {
let contig = slice::from_raw_parts(contig_data, contig_len);
let k = k as usize;
if pos + k > contig_len {
return u64::MAX;
}
for i in 0..k {
if contig[pos + i] > 3 {
return u64::MAX;
}
}
let mut kmer = Kmer::new(k as u32, KmerMode::Canonical);
for i in 0..k {
kmer.insert(contig[pos + i] as u64);
}
kmer.data()
}
}
#[no_mangle]
pub extern "C" fn ragc_remove_non_singletons(
vec_ptr: *mut u64,
vec_len: usize,
vec_capacity: usize,
virtual_begin: usize,
) -> usize {
unsafe {
let mut vec = Vec::from_raw_parts(vec_ptr, vec_len, vec_capacity);
remove_non_singletons(&mut vec, virtual_begin);
let new_len = vec.len();
std::mem::forget(vec);
new_len
}
}
#[repr(C)]
pub struct RemoveSingletonsResult {
pub vec_new_len: usize,
pub dup_new_len: usize,
}
#[no_mangle]
pub extern "C" fn ragc_remove_non_singletons_with_duplicates(
vec_ptr: *mut u64,
vec_len: usize,
vec_capacity: usize,
dup_ptr: *mut u64,
dup_len: usize,
dup_capacity: usize,
virtual_begin: usize,
) -> RemoveSingletonsResult {
unsafe {
let mut vec = Vec::from_raw_parts(vec_ptr, vec_len, vec_capacity);
let mut duplicated = Vec::from_raw_parts(dup_ptr, dup_len, dup_capacity);
remove_non_singletons_with_duplicates(&mut vec, &mut duplicated, virtual_begin);
let new_vec_len = vec.len();
let new_dup_len = duplicated.len();
std::mem::forget(vec);
std::mem::forget(duplicated);
RemoveSingletonsResult {
vec_new_len: new_vec_len,
dup_new_len: new_dup_len,
}
}
}
#[no_mangle]
pub extern "C" fn ragc_find_new_splitters_kmers(
contig_data: *const u8,
contig_len: usize,
k: u32,
candidate_kmers_ptr: *const u64,
candidate_kmers_len: usize,
candidate_kmers_offset: usize,
duplicated_kmers_ptr: *const u64,
duplicated_kmers_len: usize,
) -> KmerArray {
unsafe {
let contig = slice::from_raw_parts(contig_data, contig_len);
let candidate_kmers = slice::from_raw_parts(candidate_kmers_ptr, candidate_kmers_len);
let duplicated_kmers = slice::from_raw_parts(duplicated_kmers_ptr, duplicated_kmers_len);
let mut result = find_new_splitters_kmers(
contig,
k,
candidate_kmers,
candidate_kmers_offset,
duplicated_kmers,
);
let len = result.len();
let ptr = result.as_mut_ptr();
std::mem::forget(result);
KmerArray { data: ptr, len }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_canonical_kmers() {
let contig = vec![0, 1, 2, 3, 0, 1, 2, 3]; let k = 3;
let array = ragc_extract_canonical_kmers(contig.as_ptr(), contig.len(), k);
unsafe {
let kmers = slice::from_raw_parts(array.data, array.len);
assert_eq!(kmers.len(), 6);
}
ragc_free_kmer_array(array);
}
#[test]
fn test_extract_kmers_with_reset() {
let contig = vec![0, 1, 2, 4, 0, 1, 2, 3]; let k = 3;
let array = ragc_extract_canonical_kmers(contig.as_ptr(), contig.len(), k);
unsafe {
let kmers = slice::from_raw_parts(array.data, array.len);
assert_eq!(kmers.len(), 3);
}
ragc_free_kmer_array(array);
}
#[test]
fn test_extract_kmer_at_position() {
let contig = vec![0, 1, 2, 3, 0, 1, 2, 3]; let k = 3;
let kmer0 = ragc_extract_kmer_at_position(contig.as_ptr(), contig.len(), k, 0);
assert_ne!(kmer0, u64::MAX);
let kmer5 = ragc_extract_kmer_at_position(contig.as_ptr(), contig.len(), k, 5);
assert_ne!(kmer5, u64::MAX);
let kmer_oob = ragc_extract_kmer_at_position(contig.as_ptr(), contig.len(), k, 10);
assert_eq!(kmer_oob, u64::MAX);
}
#[test]
fn test_extract_kmer_with_n() {
let contig = vec![0, 4, 2, 3]; let k = 3;
let kmer = ragc_extract_kmer_at_position(contig.as_ptr(), contig.len(), k, 0);
assert_eq!(kmer, u64::MAX);
}
}