Skip to content

Commit 93602a6

Browse files
authored
Merge pull request #123 from shamoni/sm/mm_write_sam2
Enable passing of map_opt flags in map_to_sam method
2 parents eea1e5c + 9e2e8ce commit 93602a6

File tree

1 file changed

+52
-35
lines changed

1 file changed

+52
-35
lines changed

src/htslib.rs

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
4545
use super::ffi as mm_ffi;
4646
use crate::{Aligner, Built, Mapping, Strand, BUF};
47+
use minimap2_sys::{km_destroy, km_init};
4748
use rust_htslib::bam::header::HeaderRecord;
4849
use rust_htslib::bam::record::{Cigar, CigarString};
4950
use rust_htslib::bam::{Header, HeaderView, Record};
@@ -137,11 +138,19 @@ impl Aligner<Built> {
137138
return Err("No index");
138139
}
139140

141+
// Make sure sequence is not empty
142+
if seq.is_empty() {
143+
return Err("Sequence is empty");
144+
}
145+
140146
let query = Query::new(seq, qual, name);
141147
// Number of results
142148
let mut n_regs: i32 = 0;
143149
let mut map_opt = self.mapopt.clone();
144150

151+
// immutable raw pointer to the index
152+
let mi = &**self.idx.as_ref().unwrap().as_ref() as *const mm_ffi::mm_idx_t;
153+
145154
// TODO: other flags to consider:
146155
// MM_F_NO_PRINT_2ND
147156
// MM_F_SAM_HIT_ONLY (though this seems to be the default?)
@@ -161,11 +170,9 @@ impl Aligner<Built> {
161170
}
162171

163172
let mappings = BUF.with(|buf| {
164-
//let km = unsafe { mm_ffi::mm_tbuf_get_km(buf.borrow_mut().buf) };
165-
166173
let mm_reg = MaybeUninit::new(unsafe {
167174
mm_ffi::mm_map(
168-
&**self.idx.as_ref().unwrap().as_ref() as *const mm_ffi::mm_idx_t,
175+
mi,
169176
query.inner.l_seq,
170177
query.inner.seq as *const libc::c_char,
171178
&mut n_regs,
@@ -186,31 +193,21 @@ impl Aligner<Built> {
186193
for i in 0..n_regs {
187194
let sam_str = unsafe {
188195
let mut result: MaybeUninit<mm_ffi::kstring_t> = MaybeUninit::zeroed();
189-
let reg_ptr = (*mm_reg.as_ptr()).offset(i as isize);
190-
// // println!("{:#?}", *reg_ptr);
191-
let const_ptr = reg_ptr as *const mm_ffi::mm_reg1_t;
192-
// TODO: use mm_write_sam3 t do the writing so that we can pass the map_opt flags
193-
mm_ffi::mm_write_sam(
196+
let const_ptr = *mm_reg.as_ptr() as *const mm_ffi::mm_reg1_t;
197+
let km = km_init();
198+
mm_ffi::mm_write_sam2(
194199
result.as_mut_ptr(),
195-
&**self.idx.as_ref().unwrap().as_ref() as *const mm_ffi::mm_idx_t,
200+
mi,
196201
&query.inner as *const mm_ffi::mm_bseq1_t,
197-
const_ptr,
198-
n_regs,
199-
*mm_reg.as_ptr() as *const mm_ffi::mm_reg1_t,
202+
0,
203+
i,
204+
1,
205+
&n_regs,
206+
&const_ptr,
207+
km,
208+
map_opt.flag,
200209
);
201-
//mm_ffi::mm_write_sam3(
202-
// result.as_mut_ptr(),
203-
// self.idx.as_ref().unwrap() as *const mm_ffi::mm_idx_t,
204-
// &read as *const mm_ffi::mm_bseq1_t,
205-
// 0, // seg_idx doesn't apply here (think it's a batch index)
206-
// i,
207-
// 1, // only 1 segment
208-
// n_regs as *const i32,
209-
// &const_ptr,
210-
// km,
211-
// map_opt.flag,
212-
// 0
213-
//);
210+
km_destroy(km);
214211
CStr::from_ptr((*result.as_ptr()).s)
215212
};
216213
let record = Record::from_sam(header, sam_str.to_bytes()).unwrap();
@@ -471,7 +468,11 @@ mod tests {
471468
(aligner, idx, header_view, expected_recs, seq, qual)
472469
}
473470

474-
fn map_test_case(query_name: &str, spliced: bool) -> (Vec<Record>, Vec<Record>) {
471+
fn map_test_case(
472+
query_name: &str,
473+
spliced: bool,
474+
extra_flags: Option<Vec<u64>>,
475+
) -> (Vec<Record>, Vec<Record>) {
475476
let (aligner, _, header_view, expected, seq, qual) = get_test_case(query_name, spliced);
476477
let observed = aligner
477478
.map_to_sam(
@@ -480,7 +481,7 @@ mod tests {
480481
Some(query_name.as_bytes()),
481482
&header_view,
482483
None,
483-
None,
484+
extra_flags,
484485
)
485486
.unwrap();
486487
(observed, expected)
@@ -489,32 +490,48 @@ mod tests {
489490
#[test]
490491
fn test_fwd() {
491492
let query_name = "perfect_read.fwd";
492-
let (o, e) = map_test_case(query_name, false);
493+
let (o, e) = map_test_case(query_name, false, None);
493494
check_single_mapper(&e, &o);
494495
}
495496

496497
#[test]
497498
fn test_rev() {
498499
let query_name = "perfect_read.rev";
499-
let (o, e) = map_test_case(query_name, false);
500+
let (o, e) = map_test_case(query_name, false, None);
500501
check_single_mapper(&e, &o);
501502
}
502503

503504
#[test]
504505
fn test_mismatch() {
505506
let query_name = "imperfect_read.fwd";
506-
let (o, e) = map_test_case(query_name, false);
507+
let (o, e) = map_test_case(query_name, false, None);
507508
check_single_mapper(&e, &o);
508509

509510
let rec = o.first().unwrap();
510511
let nm = rec.aux(b"NM").unwrap();
511512
assert_eq!(nm, Aux::U8(5));
512513
}
513514

515+
#[test]
516+
fn test_aux_tag() {
517+
let query_name = "imperfect_read.fwd";
518+
let xtra_flags = vec![mm_ffi::MM_F_OUT_MD as u64];
519+
let (o, e) = map_test_case(query_name, false, Some(xtra_flags));
520+
let expected = e.first().unwrap();
521+
let observed = o.first().unwrap();
522+
if let (Ok(Aux::String(e_md)), Ok(Aux::String(o_md))) =
523+
(expected.aux(b"MD"), observed.aux(b"MD"))
524+
{
525+
assert_eq!(o_md.as_bytes(), e_md.as_bytes())
526+
} else {
527+
panic!("Could not read MD tag");
528+
}
529+
}
530+
514531
#[test]
515532
fn test_unmapped() {
516533
let query_name = "unmappable_read";
517-
let (o, e) = map_test_case(query_name, false);
534+
let (o, e) = map_test_case(query_name, false, None);
518535
check_single_mapper(&e, &o);
519536
let rec = o.first().unwrap();
520537
assert!(rec.is_unmapped());
@@ -523,7 +540,7 @@ mod tests {
523540
#[test]
524541
fn test_secondary() {
525542
let query_name = "perfect_inv_duplicate";
526-
let (o, e) = map_test_case(query_name, false);
543+
let (o, e) = map_test_case(query_name, false, None);
527544

528545
assert_eq!(o.len(), 2); // expect a primary and secondary mapping
529546
let o_fields: Vec<_> = o
@@ -544,7 +561,7 @@ mod tests {
544561
#[test]
545562
fn test_supplementary() {
546563
let query_name = "split_read";
547-
let (o, e) = map_test_case(query_name, false);
564+
let (o, e) = map_test_case(query_name, false, None);
548565

549566
assert_eq!(o.len(), 2); // expect a primary and supplementary mapping
550567
let o_fields: Vec<_> = o
@@ -562,7 +579,7 @@ mod tests {
562579
#[test]
563580
fn test_spliced() {
564581
let query_name = "cdna.fwd";
565-
let (o, e) = map_test_case(query_name, true);
582+
let (o, e) = map_test_case(query_name, true, None);
566583
check_single_mapper(&e, &o);
567584

568585
let record = o.first().unwrap();
@@ -585,7 +602,7 @@ mod tests {
585602
#[test]
586603
fn test_spliced_rev() {
587604
let query_name = "cdna.rev";
588-
let (o, e) = map_test_case(query_name, true);
605+
let (o, e) = map_test_case(query_name, true, None);
589606
check_single_mapper(&e, &o);
590607
}
591608

0 commit comments

Comments
 (0)