1use std::path::Path;
9use std::ptr;
10
11use crate::errors::{Error, Result};
12use crate::htslib;
13use crate::utils;
14
15pub enum Type {
17 Bai,
19 Csi(u32),
21}
22
23pub fn build<P: AsRef<Path>>(
25 bam_path: P,
26 idx_path: Option<P>,
27 idx_type: Type,
28 n_threads: u32,
29) -> Result<()> {
30 let min_shift = match idx_type {
31 Type::Bai => 0,
32 Type::Csi(min_shift) => min_shift as i32,
33 };
34 let idx_path_cstr;
35 let idx_path_ptr = if let Some(p) = idx_path {
36 idx_path_cstr =
37 utils::path_to_cstring(&p).expect("path_to_cstring unexpectedly returned with Err");
38 idx_path_cstr.as_ptr()
39 } else {
40 ptr::null()
41 };
42 let ret = unsafe {
43 htslib::sam_index_build3(
44 utils::path_to_cstring(&bam_path).unwrap().as_ptr(),
45 idx_path_ptr,
46 min_shift,
47 n_threads as i32,
48 )
49 };
50 match ret {
51 0 => Ok(()),
52 -1 => Err(Error::BamBuildIndex),
53 -2 => Err(Error::BamOpen {
54 target: bam_path.as_ref().to_str().unwrap().to_owned(),
55 }),
56 -3 => Err(Error::BamNotIndexable),
57 -4 => Err(Error::BamWriteIndex),
58 e => panic!("unexpected error code from sam_index_build3: {}", e),
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_index_build() {
68 let test_bam = "test/test_index_build.bam";
69
70 let idx1 = "test/results/test1.bam.bai";
72 build(test_bam, Some(idx1), Type::Bai, 1).unwrap();
73 assert!(Path::new(idx1).exists());
74
75 let idx2 = "test/results/test2.bam.bai";
77 build(test_bam, Some(idx2), Type::Bai, 2).unwrap();
78 assert!(Path::new(idx2).exists());
79
80 let idx3 = "test/results/test3.bam.csi";
82 build(test_bam, Some(idx3), Type::Csi(2), 2).unwrap();
83 assert!(Path::new(idx3).exists());
84
85 build(test_bam, None, Type::Csi(5), 2).unwrap();
87 assert!(Path::new("test/test_index_build.bam.csi").exists());
88 }
89}