1mod error;
4pub mod table;
5
6use libparasail_sys::{
7 parasail_cigar_decode, parasail_cigar_free, parasail_cigar_t, parasail_matrix_t,
8 parasail_result_free, parasail_result_get_cigar, parasail_result_get_end_query,
9 parasail_result_get_end_ref, parasail_result_get_length, parasail_result_get_length_col,
10 parasail_result_get_length_row, parasail_result_get_length_table, parasail_result_get_matches,
11 parasail_result_get_matches_col, parasail_result_get_matches_row,
12 parasail_result_get_matches_table, parasail_result_get_score, parasail_result_get_score_col,
13 parasail_result_get_score_row, parasail_result_get_score_table, parasail_result_get_similar,
14 parasail_result_get_similar_col, parasail_result_get_similar_row,
15 parasail_result_get_similar_table, parasail_result_get_trace_table,
16 parasail_result_get_traceback, parasail_result_is_banded, parasail_result_is_blocked,
17 parasail_result_is_diag, parasail_result_is_nw, parasail_result_is_rowcol,
18 parasail_result_is_saturated, parasail_result_is_scan, parasail_result_is_sg,
19 parasail_result_is_stats, parasail_result_is_stats_rowcol, parasail_result_is_stats_table,
20 parasail_result_is_striped, parasail_result_is_sw, parasail_result_is_table,
21 parasail_result_is_trace, parasail_result_ssw_free, parasail_result_ssw_t, parasail_result_t,
22 parasail_traceback_generic,
23};
24use std::ffi::CString;
25use std::slice;
26
27use crate::alignment::table::TracebackTable;
28use crate::prelude::Result;
29pub use error::Error;
30pub use table::Table;
31
32struct CigarString {
34 inner: *mut parasail_cigar_t,
35}
36
37#[doc(hidden)]
38impl Drop for CigarString {
39 fn drop(&mut self) {
40 unsafe {
41 parasail_cigar_free(self.inner);
42 }
43 }
44}
45
46pub struct Traceback {
48 pub query: String,
49 pub comparison: String,
50 pub reference: String,
51}
52
53#[derive(Debug, Clone)]
55pub struct Alignment {
56 pub(crate) inner: *mut parasail_result_t,
57 pub(crate) matrix: *const parasail_matrix_t,
58 pub(crate) query_len: i32,
59 pub(crate) ref_len: i32,
60}
61
62impl Alignment {
63 pub fn get_score(&self) -> i32 {
65 unsafe { parasail_result_get_score(self.inner) }
66 }
67
68 pub fn get_end_query(&self) -> i32 {
70 unsafe { parasail_result_get_end_query(self.inner) }
71 }
72
73 pub fn get_end_ref(&self) -> i32 {
75 unsafe { parasail_result_get_end_ref(self.inner) }
76 }
77
78 pub fn get_matches(&self) -> Result<i32> {
80 if self.is_stats() {
81 unsafe { Ok(parasail_result_get_matches(self.inner)) }
82 } else {
83 Err(Error::NoStats(String::from("get_matches()")))?
84 }
85 }
86
87 pub fn get_similar(&self) -> i32 {
88 unsafe { parasail_result_get_similar(self.inner) }
89 }
90
91 pub fn get_length(&self) -> Result<i32> {
93 if self.is_stats() {
94 unsafe { Ok(parasail_result_get_length(self.inner)) }
95 } else {
96 Err(Error::NoStats(String::from("get_length()")))?
97 }
98 }
99
100 pub fn get_score_table(&self) -> Result<Table<'_>> {
124 if self.is_table() || self.is_stats_table() {
125 unsafe {
126 let table_ptr = parasail_result_get_score_table(self.inner);
127 let table_size = (self.query_len * self.ref_len) as usize;
128 let data = slice::from_raw_parts(table_ptr, table_size);
129 Ok(Table::new(
130 data,
131 self.query_len as usize,
132 self.ref_len as usize,
133 ))
134 }
135 } else {
136 Err(Error::NoTable(String::from("get_score_table()")))?
137 }
138 }
139
140 pub fn get_matches_table(&self) -> Result<Table<'_>> {
142 if self.is_stats_table() {
143 unsafe {
144 let table_ptr = parasail_result_get_matches_table(self.inner);
145 let table_size = (self.query_len * self.ref_len) as usize;
146 let data = slice::from_raw_parts(table_ptr, table_size);
147 Ok(Table::new(
148 data,
149 self.query_len as usize,
150 self.ref_len as usize,
151 ))
152 }
153 } else {
154 Err(Error::NoStatsTable(String::from("get_matches_table()")))?
155 }
156 }
157
158 pub fn get_similar_table(&self) -> Result<Table<'_>> {
160 if self.is_stats_table() {
161 unsafe {
162 let table_ptr = parasail_result_get_similar_table(self.inner);
163 let table_size = (self.query_len * self.ref_len) as usize;
164 let data = slice::from_raw_parts(table_ptr, table_size);
165 Ok(Table::new(
166 data,
167 self.query_len as usize,
168 self.ref_len as usize,
169 ))
170 }
171 } else {
172 Err(Error::NoStatsTable(String::from("get_similar_table()")))?
173 }
174 }
175
176 pub fn get_length_table(&self) -> Result<Table<'_>> {
178 if self.is_stats_table() {
179 unsafe {
180 let table_ptr = parasail_result_get_length_table(self.inner);
181 let table_size = (self.query_len * self.ref_len) as usize;
182 let data = slice::from_raw_parts(table_ptr, table_size);
183 Ok(Table::new(
184 data,
185 self.query_len as usize,
186 self.ref_len as usize,
187 ))
188 }
189 } else {
190 Err(Error::NoStatsTable(String::from("get_length_table()")))?
191 }
192 }
193
194 pub fn get_score_row(&self) -> Result<&[i32]> {
196 if self.is_rowcol() || self.is_stats_rowcol() {
197 unsafe {
198 let rptr = parasail_result_get_score_row(self.inner);
199 Ok(slice::from_raw_parts(rptr, self.ref_len as usize))
200 }
201 } else {
202 Err(Error::NoRowCol(String::from("get_score_row()")))?
203 }
204 }
205
206 pub fn get_matches_row(&self) -> Result<&[i32]> {
208 if self.is_stats_rowcol() {
209 unsafe {
210 let rptr = parasail_result_get_matches_row(self.inner);
211 Ok(slice::from_raw_parts(rptr, self.ref_len as usize))
212 }
213 } else {
214 Err(Error::NoRowCol(String::from("get_matches_row()")))?
215 }
216 }
217
218 pub fn get_similar_row(&self) -> Result<&[i32]> {
220 if self.is_stats_rowcol() {
221 unsafe {
222 let rptr = parasail_result_get_similar_row(self.inner);
223 Ok(slice::from_raw_parts(rptr, self.ref_len as usize))
224 }
225 } else {
226 Err(Error::NoRowCol(String::from("get_similar_row()")))?
227 }
228 }
229
230 pub fn get_length_row(&self) -> Result<&[i32]> {
232 if self.is_stats_rowcol() {
233 unsafe {
234 let rptr = parasail_result_get_length_row(self.inner);
235 Ok(slice::from_raw_parts(rptr, self.ref_len as usize))
236 }
237 } else {
238 Err(Error::NoRowCol(String::from("get_length_row()")))?
239 }
240 }
241
242 pub fn get_score_col(&self) -> Result<&[i32]> {
244 if self.is_rowcol() || self.is_stats_rowcol() {
245 unsafe {
246 let cptr = parasail_result_get_score_col(self.inner);
247 Ok(slice::from_raw_parts(cptr, self.query_len as usize))
248 }
249 } else {
250 Err(Error::NoRowCol(String::from("get_score_col()")))?
251 }
252 }
253
254 pub fn get_matches_col(&self) -> Result<&[i32]> {
256 if self.is_stats_rowcol() {
257 unsafe {
258 let cptr = parasail_result_get_matches_col(self.inner);
259 Ok(slice::from_raw_parts(cptr, self.query_len as usize))
260 }
261 } else {
262 Err(Error::NoRowCol(String::from("get_matches_col()")))?
263 }
264 }
265
266 pub fn get_similar_col(&self) -> Result<&[i32]> {
268 if self.is_stats_rowcol() {
269 unsafe {
270 let cptr = parasail_result_get_similar_col(self.inner);
271 Ok(slice::from_raw_parts(cptr, self.query_len as usize))
272 }
273 } else {
274 Err(Error::NoRowCol(String::from("get_similar_col()")))?
275 }
276 }
277
278 pub fn get_length_col(&self) -> Result<&[i32]> {
280 if self.is_stats_rowcol() {
281 unsafe {
282 let cptr = parasail_result_get_length_col(self.inner);
283 Ok(slice::from_raw_parts(cptr, self.query_len as usize))
284 }
285 } else {
286 Err(Error::NoRowCol(String::from("get_length_col()")))?
287 }
288 }
289
290 pub fn get_trace_table(&self) -> Result<TracebackTable<'_>> {
292 if self.is_trace() {
293 unsafe {
294 let table_ptr = parasail_result_get_trace_table(self.inner) as *const i8;
295 let table_size = (self.query_len * self.ref_len) as usize;
296 let data = slice::from_raw_parts(table_ptr, table_size);
297
298 Ok(TracebackTable::new(
299 data,
300 self.query_len as usize,
301 self.ref_len as usize,
302 ))
303 }
304 } else {
305 Err(Error::NoTrace(String::from("get_trace_table()")))?
306 }
307 }
308
309 pub fn print_traceback(&self, query: &[u8], reference: &[u8]) {
311 if self.is_trace() {
312 let query_len = query.len() as i32;
313 let ref_len = reference.len() as i32;
314 let query = CString::new(query).unwrap();
315 let reference = CString::new(reference).unwrap();
316 let query_str = CString::new("Query:").unwrap();
317 let ref_str = CString::new("Target:").unwrap();
318 let match_char = CString::new("|").unwrap();
319 let mismatch_char = CString::new(" ").unwrap();
320 let width = 80;
321 let name_width = 7;
322 let use_stats = 1;
323 unsafe {
324 parasail_traceback_generic(
325 query.as_ptr(),
326 query_len,
327 reference.as_ptr(),
328 ref_len,
329 query_str.as_ptr(),
330 ref_str.as_ptr(),
331 self.matrix,
332 self.inner,
333 *match_char.as_ptr(),
334 *mismatch_char.as_ptr(),
335 *mismatch_char.as_ptr(),
336 width,
337 name_width,
338 use_stats,
339 );
340 }
341 } else {
342 println!("Alignment string is not available without traceback enabled. Consider using the `use_trace` method on AlignerBuilder.");
343 }
344 }
345
346 pub fn get_traceback_strings(&self, query: &[u8], reference: &[u8]) -> Result<Traceback> {
348 if self.is_trace() {
349 let query_len = query.len() as i32;
350 let ref_len = reference.len() as i32;
351 let query = CString::new(query).map_err(Error::InteriorNulByte)?;
352 let reference = CString::new(reference).map_err(Error::InteriorNulByte)?;
353 let match_char = CString::new("|").map_err(Error::InteriorNulByte)?;
354 let mismatch_char = CString::new(" ").map_err(Error::InteriorNulByte)?;
355 unsafe {
356 let alignment = parasail_result_get_traceback(
357 self.inner,
358 query.as_ptr(),
359 query_len,
360 reference.as_ptr(),
361 ref_len,
362 self.matrix,
363 *match_char.as_ptr(),
364 *mismatch_char.as_ptr(),
365 *mismatch_char.as_ptr(),
366 );
367
368 let query_traceback = CString::from_raw((*alignment).query)
369 .into_string()
370 .map_err(Error::InvalidUTF8String)?;
371 let comparison_traceback = CString::from_raw((*alignment).comp)
372 .into_string()
373 .map_err(Error::InvalidUTF8String)?;
374 let reference_traceback = CString::from_raw((*alignment).ref_)
375 .into_string()
376 .map_err(Error::InvalidUTF8String)?;
377
378 Ok(Traceback {
379 query: query_traceback.clone(),
380 comparison: comparison_traceback.clone(),
381 reference: reference_traceback.clone(),
382 })
383 }
384 } else {
385 Err(Error::NoTrace(String::from("get_traceback_strings()")))?
386 }
387 }
388
389 pub fn get_cigar(&self, query: &[u8], reference: &[u8]) -> Result<String> {
391 if self.is_trace() {
392 let query_len = query.len() as i32;
393 let query = CString::new(query).map_err(Error::InteriorNulByte)?;
394 let ref_len = reference.len() as i32;
395 let reference = CString::new(reference).map_err(Error::InteriorNulByte)?;
396
397 let cigar: String;
398 unsafe {
399 let cigar_encoded = CigarString {
400 inner: parasail_result_get_cigar(
401 self.inner,
402 query.as_ptr(),
403 query_len,
404 reference.as_ptr(),
405 ref_len,
406 self.matrix,
407 ),
408 };
409
410 cigar = CString::from_raw(parasail_cigar_decode(cigar_encoded.inner))
411 .into_string()
412 .map_err(Error::InvalidUTF8String)?;
413 }
414
415 Ok(cigar)
416 } else {
417 Err(Error::NoTrace(String::from("get_cigar()")).into())
418 }
419 }
420
421 pub fn is_global(&self) -> bool {
423 unsafe { parasail_result_is_nw(self.inner) != 0 }
424 }
425
426 pub fn is_semi_global(&self) -> bool {
428 unsafe { parasail_result_is_sg(self.inner) != 0 }
429 }
430
431 pub fn is_local(&self) -> bool {
433 unsafe { parasail_result_is_sw(self.inner) != 0 }
434 }
435
436 pub fn is_saturated(&self) -> bool {
439 unsafe { parasail_result_is_saturated(self.inner) != 0 }
440 }
441
442 pub fn is_banded(&self) -> bool {
444 unsafe { parasail_result_is_banded(self.inner) != 0 }
445 }
446
447 pub fn is_scan(&self) -> bool {
449 unsafe { parasail_result_is_scan(self.inner) != 0 }
450 }
451
452 pub fn is_striped(&self) -> bool {
454 unsafe { parasail_result_is_striped(self.inner) != 0 }
455 }
456
457 pub fn is_diag(&self) -> bool {
459 unsafe { parasail_result_is_diag(self.inner) != 0 }
460 }
461
462 pub fn is_blocked(&self) -> bool {
463 unsafe { parasail_result_is_blocked(self.inner) != 0 }
464 }
465
466 pub fn is_stats(&self) -> bool {
468 unsafe { parasail_result_is_stats(self.inner) != 0 }
469 }
470
471 pub fn is_stats_table(&self) -> bool {
473 unsafe { parasail_result_is_stats_table(self.inner) != 0 }
474 }
475
476 pub fn is_table(&self) -> bool {
478 unsafe { parasail_result_is_table(self.inner) != 0 }
479 }
480
481 pub fn is_rowcol(&self) -> bool {
483 unsafe { parasail_result_is_rowcol(self.inner) != 0 }
484 }
485
486 pub fn is_stats_rowcol(&self) -> bool {
488 unsafe { parasail_result_is_stats_rowcol(self.inner) != 0 }
489 }
490
491 pub fn is_trace(&self) -> bool {
493 unsafe { parasail_result_is_trace(self.inner) != 0 }
494 }
495}
496
497#[doc(hidden)]
498impl Drop for Alignment {
499 fn drop(&mut self) {
500 unsafe {
501 parasail_result_free(self.inner);
502 }
503 }
504}
505
506pub struct SSWResult {
508 pub(crate) inner: *mut parasail_result_ssw_t,
509}
510
511impl SSWResult {
512 pub fn score(&self) -> u16 {
514 unsafe { (*self.inner).score1 }
515 }
516
517 pub fn ref_start(&self) -> i32 {
519 unsafe { (*self.inner).ref_begin1 }
520 }
521
522 pub fn ref_end(&self) -> i32 {
524 unsafe { (*self.inner).ref_end1 }
525 }
526
527 pub fn query_start(&self) -> i32 {
529 unsafe { (*self.inner).read_begin1 }
530 }
531
532 pub fn query_end(&self) -> i32 {
534 unsafe { (*self.inner).read_end1 }
535 }
536
537 pub fn cigar(&self) -> *mut u32 {
538 unsafe { (*self.inner).cigar }
539 }
540
541 pub fn cigar_len(&self) -> i32 {
542 unsafe { (*self.inner).cigarLen }
543 }
544}
545
546#[doc(hidden)]
547impl Drop for SSWResult {
548 fn drop(&mut self) {
549 unsafe { parasail_result_ssw_free(self.inner) }
550 }
551}