block_aligner/
ffi.rs

1//! C bindings for block aligner.
2//!
3//! Generics are monomorphised manually.
4//!
5//! Nucleotide and arbitrary byte alignment do not have bindings yet.
6
7use std::ffi::c_void;
8
9use crate::scan_block::*;
10use crate::scores::*;
11use crate::cigar::*;
12
13// avoid generics by using void pointer and monomorphism
14/// A handle for a block in block aligner.
15pub type BlockHandle = *mut c_void;
16
17/// Represents a range that has inclusive lower and upper bounds.
18#[derive(Copy, Clone, PartialEq)]
19#[repr(C)]
20pub struct SizeRange {
21    pub min: usize,
22    pub max: usize
23}
24
25
26// AAMatrix
27
28/// Create a new simple AAMatrix with custom match and mismatch scores.
29///
30/// Note that the match score must be positive and the mismatch score must be negative.
31#[no_mangle]
32pub unsafe extern fn block_new_simple_aamatrix(match_score: i8, mismatch_score: i8) -> *mut AAMatrix {
33    let matrix = Box::new(AAMatrix::new_simple(match_score, mismatch_score));
34    Box::into_raw(matrix)
35}
36
37/// Set an entry in the AAMatrix.
38#[no_mangle]
39pub unsafe extern fn block_set_aamatrix(matrix: *mut AAMatrix, a: u8, b: u8, score: i8) {
40    let matrix = &mut *matrix;
41    matrix.set(a, b, score);
42}
43
44/// Frees an AAMatrix.
45#[no_mangle]
46pub unsafe extern fn block_free_aamatrix(matrix: *mut AAMatrix) {
47    drop(Box::from_raw(matrix));
48}
49
50
51// AAProfile
52
53/// Create a new profile of a specific length, with default (large negative) values.
54///
55/// Note that internally, the created profile is longer than a conventional position-specific scoring
56/// matrix (and `str_len`) by 1, so the profile will have the same length as the number of
57/// columns in the DP matrix.
58/// The first column of scores in the profile should be large negative values (padding).
59/// This allows gap open costs to be specified for the first column of the DP matrix.
60#[no_mangle]
61pub unsafe extern fn block_new_aaprofile(str_len: usize, block_size: usize, gap_extend: i8) -> *mut AAProfile {
62    let profile = Box::new(AAProfile::new(str_len, block_size, gap_extend));
63    Box::into_raw(profile)
64}
65
66/// Get the length of the profile.
67#[no_mangle]
68pub unsafe extern fn block_len_aaprofile(profile: *const AAProfile) -> usize {
69    let profile = &*profile;
70    profile.len()
71}
72
73/// Clear the profile so it can be reused for profile lengths less than or equal
74/// to the length this struct was created with.
75#[no_mangle]
76pub unsafe extern fn block_clear_aaprofile(profile: *mut AAProfile, str_len: usize, block_size: usize) {
77    let profile = &mut *profile;
78    profile.clear(str_len, block_size);
79}
80
81/// Set the score for a position and byte.
82///
83/// The profile should be first `clear`ed before it is reused with different lengths.
84///
85/// The first column (`i = 0`) should be padded with large negative values.
86/// Therefore, set values starting from `i = 1`.
87#[no_mangle]
88pub unsafe extern fn block_set_aaprofile(profile: *mut AAProfile, i: usize, b: u8, score: i8) {
89    let profile = &mut *profile;
90    profile.set(i, b, score);
91}
92
93/// Set the scores for all positions in the position specific scoring matrix.
94///
95/// The profile should be first `clear`ed before it is reused with different lengths.
96///
97/// Use `order` to specify the order of bytes that is used in the `scores` matrix.
98/// Scores (in `scores`) should be stored in row-major order, where each row is a different position
99/// and each column is a different byte.
100#[no_mangle]
101pub unsafe extern fn block_set_all_aaprofile(profile: *mut AAProfile, order: *const u8, order_len: usize, scores: *const i8, scores_len: usize, left_shift: usize, right_shift: usize) {
102    let profile = &mut *profile;
103    let order = std::slice::from_raw_parts(order, order_len);
104    let scores = std::slice::from_raw_parts(scores, scores_len);
105    profile.set_all(order, scores, left_shift, right_shift);
106}
107
108/// Set the scores for all positions in reverse in the position specific scoring matrix.
109///
110/// The profile should be first `clear`ed before it is reused with different lengths.
111///
112/// Use `order` to specify the order of bytes that is used in the `scores` matrix.
113/// Scores (in `scores`) should be stored in row-major order, where each row is a different position
114/// and each column is a different byte.
115#[no_mangle]
116pub unsafe extern fn block_set_all_rev_aaprofile(profile: *mut AAProfile, order: *const u8, order_len: usize, scores: *const i8, scores_len: usize, left_shift: usize, right_shift: usize) {
117    let profile = &mut *profile;
118    let order = std::slice::from_raw_parts(order, order_len);
119    let scores = std::slice::from_raw_parts(scores, scores_len);
120    profile.set_all_rev(order, scores, left_shift, right_shift);
121}
122
123/// Set the gap open cost for a column.
124///
125/// When aligning a sequence `q` to a profile `r`, this is the gap open cost at column `i` for a
126/// column transition in the DP matrix with `|q| + 1` rows and `|r| + 1` columns.
127/// This represents starting a gap in `q`.
128#[no_mangle]
129pub unsafe extern fn block_set_gap_open_C_aaprofile(profile: *mut AAProfile, i: usize, gap: i8) {
130    let profile = &mut *profile;
131    profile.set_gap_open_C(i, gap);
132}
133
134/// Set the gap close cost for a column.
135///
136/// When aligning a sequence `q` to a profile `r`, this is the gap close cost at column `i` for
137/// ending column transitions in the DP matrix with `|q| + 1` rows and `|r| + 1` columns.
138/// This represents ending a gap in `q`.
139#[no_mangle]
140pub unsafe extern fn block_set_gap_close_C_aaprofile(profile: *mut AAProfile, i: usize, gap: i8) {
141    let profile = &mut *profile;
142    profile.set_gap_close_C(i, gap);
143}
144
145/// Set the gap open cost for a row.
146///
147/// When aligning a sequence `q` to a profile `r`, this is the gap open cost at column `i` for
148/// a row transition in the DP matrix with `|q| + 1` rows and `|r| + 1` columns.
149/// This represents starting a gap in `r`.
150#[no_mangle]
151pub unsafe extern fn block_set_gap_open_R_aaprofile(profile: *mut AAProfile, i: usize, gap: i8) {
152    let profile = &mut *profile;
153    profile.set_gap_open_R(i, gap);
154}
155
156/// Set the gap open cost for all column transitions.
157#[no_mangle]
158pub unsafe extern fn block_set_all_gap_open_C_aaprofile(profile: *mut AAProfile, gap: i8) {
159    let profile = &mut *profile;
160    profile.set_all_gap_open_C(gap);
161}
162
163/// Set the gap close cost for all column transitions.
164#[no_mangle]
165pub unsafe extern fn block_set_all_gap_close_C_aaprofile(profile: *mut AAProfile, gap: i8) {
166    let profile = &mut *profile;
167    profile.set_all_gap_close_C(gap);
168}
169
170/// Set the gap open cost for all row transitions.
171#[no_mangle]
172pub unsafe extern fn block_set_all_gap_open_R_aaprofile(profile: *mut AAProfile, gap: i8) {
173    let profile = &mut *profile;
174    profile.set_all_gap_open_R(gap);
175}
176
177/// Get the score for a position and byte.
178#[no_mangle]
179pub unsafe extern fn block_get_aaprofile(profile: *const AAProfile, i: usize, b: u8) -> i8 {
180    let profile = &*profile;
181    profile.get(i, b)
182}
183
184/// Get the gap extend cost.
185#[no_mangle]
186pub unsafe extern fn block_get_gap_extend_aaprofile(profile: *const AAProfile) -> i8 {
187    let profile = &*profile;
188    profile.get_gap_extend()
189}
190
191/// Frees an AAProfile.
192#[no_mangle]
193pub unsafe extern fn block_free_aaprofile(profile: *mut AAProfile) {
194    drop(Box::from_raw(profile));
195}
196
197
198// CIGAR
199
200/// Create a new empty CIGAR string.
201#[no_mangle]
202pub unsafe extern fn block_new_cigar(query_len: usize, reference_len: usize) -> *mut Cigar {
203    let cigar = Box::new(Cigar::new(query_len, reference_len));
204    Box::into_raw(cigar)
205}
206
207/// Get the operation at a certain index in a CIGAR string.
208#[no_mangle]
209pub unsafe extern fn block_get_cigar(cigar: *const Cigar, i: usize) -> OpLen {
210    let cigar_str = &*cigar;
211    cigar_str.get(i)
212}
213
214/// Get the length of a CIGAR string.
215#[no_mangle]
216pub unsafe extern fn block_len_cigar(cigar: *const Cigar) -> usize {
217    let cigar_str = &*cigar;
218    cigar_str.len()
219}
220
221/// Frees a CIGAR string.
222#[no_mangle]
223pub unsafe extern fn block_free_cigar(cigar: *mut Cigar) {
224    drop(Box::from_raw(cigar));
225}
226
227
228// PaddedBytes
229
230/// Create a new empty padded amino acid string.
231#[no_mangle]
232pub unsafe extern fn block_new_padded_aa(len: usize, max_size: usize) -> *mut PaddedBytes {
233    let padded_bytes = Box::new(PaddedBytes::new::<AAMatrix>(len, max_size));
234    Box::into_raw(padded_bytes)
235}
236
237/// Write to a padded amino acid string.
238#[no_mangle]
239pub unsafe extern fn block_set_bytes_padded_aa(padded: *mut PaddedBytes, s: *const u8, len: usize, max_size: usize) {
240    let bytes = std::slice::from_raw_parts(s, len);
241    let padded_bytes = &mut *padded;
242    padded_bytes.set_bytes::<AAMatrix>(bytes, max_size);
243}
244
245/// Write to a padded amino acid string, in reverse.
246#[no_mangle]
247pub unsafe extern fn block_set_bytes_rev_padded_aa(padded: *mut PaddedBytes, s: *const u8, len: usize, max_size: usize) {
248    let bytes = std::slice::from_raw_parts(s, len);
249    let padded_bytes = &mut *padded;
250    padded_bytes.set_bytes_rev::<AAMatrix>(bytes, max_size);
251}
252
253/// Frees a padded amino acid string.
254#[no_mangle]
255pub unsafe extern fn block_free_padded_aa(padded: *mut PaddedBytes) {
256    drop(Box::from_raw(padded));
257}
258
259
260// Block
261
262macro_rules! gen_functions {
263    ($new_name:ident, $new_doc:expr,
264     $align_name:ident, $align_doc:expr,
265     $align_profile_name:ident, $align_profile_doc:expr,
266     $res_name:ident, $res_doc:expr,
267     $trace_name:ident, $trace_doc:expr,
268     $trace_eq_name:ident, $trace_eq_doc:expr,
269     $free_name:ident, $free_doc:expr,
270     $matrix:ty, $profile:ty, $trace:literal, $x_drop:literal) => {
271        #[doc = $new_doc]
272        #[no_mangle]
273        pub unsafe extern fn $new_name(query_len: usize,
274                                       reference_len: usize,
275                                       max_size: usize) -> BlockHandle {
276            let aligner = Box::new(Block::<$trace, $x_drop>::new(query_len, reference_len, max_size));
277            Box::into_raw(aligner) as BlockHandle
278        }
279
280        #[doc = $align_doc]
281        #[no_mangle]
282        pub unsafe extern fn $align_name(b: BlockHandle,
283                                         q: *const PaddedBytes,
284                                         r: *const PaddedBytes,
285                                         m: *const $matrix,
286                                         g: Gaps,
287                                         s: SizeRange,
288                                         x: i32) {
289            let aligner = &mut *(b as *mut Block<$trace, $x_drop>);
290            aligner.align(&*q, &*r, &*m, g, s.min..=s.max, x);
291        }
292
293        #[doc = $align_profile_doc]
294        #[no_mangle]
295        pub unsafe extern fn $align_profile_name(b: BlockHandle,
296                                                 q: *const PaddedBytes,
297                                                 r: *const $profile,
298                                                 s: SizeRange,
299                                                 x: i32) {
300            let aligner = &mut *(b as *mut Block<$trace, $x_drop>);
301            aligner.align_profile(&*q, &*r, s.min..=s.max, x);
302        }
303
304        #[doc = $res_doc]
305        #[no_mangle]
306        pub unsafe extern fn $res_name(b: BlockHandle) -> AlignResult {
307            let aligner = &*(b as *const Block<$trace, $x_drop>);
308            aligner.res()
309        }
310
311        #[doc = $trace_doc]
312        #[no_mangle]
313        pub unsafe extern fn $trace_name(b: BlockHandle, query_idx: usize, reference_idx: usize, cigar: *mut Cigar) {
314            let aligner = &*(b as *const Block<$trace, $x_drop>);
315            aligner.trace().cigar(query_idx, reference_idx, &mut *cigar);
316        }
317
318        #[doc = $trace_eq_doc]
319        #[no_mangle]
320        pub unsafe extern fn $trace_eq_name(b: BlockHandle, q: *const PaddedBytes, r: *const PaddedBytes, query_idx: usize, reference_idx: usize, cigar: *mut Cigar) {
321            let aligner = &*(b as *const Block<$trace, $x_drop>);
322            aligner.trace().cigar_eq(&*q, &*r, query_idx, reference_idx, &mut *cigar);
323        }
324
325        #[doc = $free_doc]
326        #[no_mangle]
327        pub unsafe extern fn $free_name(b: BlockHandle) {
328            drop(Box::from_raw(b as *mut Block<$trace, $x_drop>));
329        }
330    };
331}
332
333gen_functions!(
334    block_new_aa,
335    "Create a new block aligner instance for global alignment of amino acid strings (no traceback).",
336    block_align_aa,
337    "Global alignment of two amino acid strings (no traceback).",
338    block_align_profile_aa,
339    "Global alignment of an amino acid sequence to a profile (no traceback).",
340    block_res_aa,
341    "Retrieves the result of global alignment of two amino acid strings (no traceback).",
342    _block_cigar_aa,
343    "Don't use.",
344    _block_cigar_eq_aa,
345    "Don't use.",
346    block_free_aa,
347    "Frees the block used for global alignment of two amino acid strings (no traceback).",
348    AAMatrix, AAProfile, false, false
349);
350
351gen_functions!(
352    block_new_aa_xdrop,
353    "Create a new block aligner instance for X-drop alignment of amino acid strings (no traceback).",
354    block_align_aa_xdrop,
355    "X-drop alignment of two amino acid strings (no traceback).",
356    block_align_profile_aa_xdrop,
357    "X-drop alignment of an amino acid sequence to a profile (no traceback).",
358    block_res_aa_xdrop,
359    "Retrieves the result of X-drop alignment of two amino acid strings (no traceback).",
360    _block_cigar_aa_xdrop,
361    "Don't use.",
362    _block_cigar_eq_aa_xdrop,
363    "Don't use.",
364    block_free_aa_xdrop,
365    "Frees the block used for X-drop alignment of two amino acid strings (no traceback).",
366    AAMatrix, AAProfile, false, true
367);
368
369gen_functions!(
370    block_new_aa_trace,
371    "Create a new block aligner instance for global alignment of amino acid strings, with traceback.",
372    block_align_aa_trace,
373    "Global alignment of two amino acid strings, with traceback.",
374    block_align_profile_aa_trace,
375    "Global alignment of an amino acid sequence to a profile, with traceback.",
376    block_res_aa_trace,
377    "Retrieves the result of global alignment of two amino acid strings, with traceback.",
378    block_cigar_aa_trace,
379    "Retrieves the resulting CIGAR string from global alignment of two amino acid strings, with traceback.",
380    block_cigar_eq_aa_trace,
381    "Retrieves the resulting CIGAR string from global alignment of two amino acid strings, with traceback containing =/X.",
382    block_free_aa_trace,
383    "Frees the block used for global alignment of two amino acid strings, with traceback.",
384    AAMatrix, AAProfile, true, false
385);
386
387gen_functions!(
388    block_new_aa_trace_xdrop,
389    "Create a new block aligner instance for X-drop alignment of amino acid strings, with traceback.",
390    block_align_aa_trace_xdrop,
391    "X-drop alignment of two amino acid strings, with traceback.",
392    block_align_profile_aa_trace_xdrop,
393    "X-drop alignment of an amino acid sequence to a profile, with traceback.",
394    block_res_aa_trace_xdrop,
395    "Retrieves the result of X-drop alignment of two amino acid strings, with traceback.",
396    block_cigar_aa_trace_xdrop,
397    "Retrieves the resulting CIGAR string from X-drop alignment of two amino acid strings, with traceback.",
398    block_cigar_eq_aa_trace_xdrop,
399    "Retrieves the resulting CIGAR string from X-drop alignment of two amino acid strings, with traceback containing =/X.",
400    block_free_aa_trace_xdrop,
401    "Frees the block used for X-drop alignment of two amino acid strings, with traceback.",
402    AAMatrix, AAProfile, true, true
403);