#[no_mangle]
pub extern "C" fn ragc_is_valid_base(base: u8) -> bool {
base <= 3
}
#[no_mangle]
pub extern "C" fn ragc_should_reset_kmer(base: u8) -> bool {
base > 3
}
#[repr(C)]
pub struct BaseCounts {
pub n_valid: usize,
pub n_invalid: usize,
}
#[no_mangle]
pub extern "C" fn ragc_count_base_validity(sequence: *const u8, length: usize) -> BaseCounts {
unsafe {
let seq = std::slice::from_raw_parts(sequence, length);
let mut n_valid = 0;
let mut n_invalid = 0;
for &base in seq {
if ragc_is_valid_base(base) {
n_valid += 1;
} else {
n_invalid += 1;
}
}
BaseCounts { n_valid, n_invalid }
}
}
#[repr(C)]
pub struct PositionArray {
pub data: *mut usize,
pub len: usize,
}
#[no_mangle]
pub extern "C" fn ragc_find_invalid_base_positions(
sequence: *const u8,
length: usize,
) -> PositionArray {
unsafe {
let seq = std::slice::from_raw_parts(sequence, length);
let mut positions: Vec<usize> = seq
.iter()
.enumerate()
.filter(|(_, &base)| !ragc_is_valid_base(base))
.map(|(pos, _)| pos)
.collect();
let ptr = positions.as_mut_ptr();
let len = positions.len();
std::mem::forget(positions);
PositionArray { data: ptr, len }
}
}
#[no_mangle]
pub extern "C" fn ragc_free_position_array(array: PositionArray) {
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_valid_bases() {
assert!(ragc_is_valid_base(0)); assert!(ragc_is_valid_base(1)); assert!(ragc_is_valid_base(2)); assert!(ragc_is_valid_base(3));
assert!(!ragc_is_valid_base(4)); assert!(!ragc_is_valid_base(5));
assert!(!ragc_is_valid_base(255));
}
#[test]
fn test_should_reset() {
assert!(!ragc_should_reset_kmer(0));
assert!(!ragc_should_reset_kmer(1));
assert!(!ragc_should_reset_kmer(2));
assert!(!ragc_should_reset_kmer(3));
assert!(ragc_should_reset_kmer(4));
assert!(ragc_should_reset_kmer(5));
assert!(ragc_should_reset_kmer(255));
}
#[test]
fn test_count_validity() {
let sequence = vec![0, 1, 2, 3, 4, 0, 1, 5]; let counts = ragc_count_base_validity(sequence.as_ptr(), sequence.len());
assert_eq!(counts.n_valid, 6); assert_eq!(counts.n_invalid, 2); }
#[test]
fn test_find_invalid_positions() {
let sequence = vec![0, 1, 4, 2, 3, 5, 0]; let positions = ragc_find_invalid_base_positions(sequence.as_ptr(), sequence.len());
unsafe {
let pos_slice = std::slice::from_raw_parts(positions.data, positions.len);
assert_eq!(pos_slice, &[2, 5]); }
ragc_free_position_array(positions);
}
#[test]
fn test_all_valid() {
let sequence = vec![0, 1, 2, 3, 0, 1, 2, 3]; let positions = ragc_find_invalid_base_positions(sequence.as_ptr(), sequence.len());
assert_eq!(positions.len, 0);
ragc_free_position_array(positions);
}
}