ragc_core/ffi/
base_validation.rs1#[no_mangle]
25pub extern "C" fn ragc_is_valid_base(base: u8) -> bool {
26 base <= 3
30}
31
32#[no_mangle]
39pub extern "C" fn ragc_should_reset_kmer(base: u8) -> bool {
40 base > 3
41}
42
43#[repr(C)]
47pub struct BaseCounts {
48 pub n_valid: usize,
49 pub n_invalid: usize,
50}
51
52#[no_mangle]
53pub extern "C" fn ragc_count_base_validity(sequence: *const u8, length: usize) -> BaseCounts {
54 unsafe {
55 let seq = std::slice::from_raw_parts(sequence, length);
56
57 let mut n_valid = 0;
58 let mut n_invalid = 0;
59
60 for &base in seq {
61 if ragc_is_valid_base(base) {
62 n_valid += 1;
63 } else {
64 n_invalid += 1;
65 }
66 }
67
68 BaseCounts { n_valid, n_invalid }
69 }
70}
71
72#[repr(C)]
81pub struct PositionArray {
82 pub data: *mut usize,
83 pub len: usize,
84}
85
86#[no_mangle]
87pub extern "C" fn ragc_find_invalid_base_positions(
88 sequence: *const u8,
89 length: usize,
90) -> PositionArray {
91 unsafe {
92 let seq = std::slice::from_raw_parts(sequence, length);
93
94 let mut positions: Vec<usize> = seq
95 .iter()
96 .enumerate()
97 .filter(|(_, &base)| !ragc_is_valid_base(base))
98 .map(|(pos, _)| pos)
99 .collect();
100
101 let ptr = positions.as_mut_ptr();
102 let len = positions.len();
103
104 std::mem::forget(positions);
105
106 PositionArray { data: ptr, len }
107 }
108}
109
110#[no_mangle]
111pub extern "C" fn ragc_free_position_array(array: PositionArray) {
112 unsafe {
113 if !array.data.is_null() && array.len > 0 {
114 let _ = Vec::from_raw_parts(array.data, array.len, array.len);
115 }
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_valid_bases() {
125 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));
134 assert!(!ragc_is_valid_base(255));
135 }
136
137 #[test]
138 fn test_should_reset() {
139 assert!(!ragc_should_reset_kmer(0));
141 assert!(!ragc_should_reset_kmer(1));
142 assert!(!ragc_should_reset_kmer(2));
143 assert!(!ragc_should_reset_kmer(3));
144
145 assert!(ragc_should_reset_kmer(4));
147 assert!(ragc_should_reset_kmer(5));
148 assert!(ragc_should_reset_kmer(255));
149 }
150
151 #[test]
152 fn test_count_validity() {
153 let sequence = vec![0, 1, 2, 3, 4, 0, 1, 5]; let counts = ragc_count_base_validity(sequence.as_ptr(), sequence.len());
155
156 assert_eq!(counts.n_valid, 6); assert_eq!(counts.n_invalid, 2); }
159
160 #[test]
161 fn test_find_invalid_positions() {
162 let sequence = vec![0, 1, 4, 2, 3, 5, 0]; let positions = ragc_find_invalid_base_positions(sequence.as_ptr(), sequence.len());
164
165 unsafe {
166 let pos_slice = std::slice::from_raw_parts(positions.data, positions.len);
167 assert_eq!(pos_slice, &[2, 5]); }
169
170 ragc_free_position_array(positions);
171 }
172
173 #[test]
174 fn test_all_valid() {
175 let sequence = vec![0, 1, 2, 3, 0, 1, 2, 3]; let positions = ragc_find_invalid_base_positions(sequence.as_ptr(), sequence.len());
177
178 assert_eq!(positions.len, 0); ragc_free_position_array(positions);
181 }
182}