noodles_bam/io/indexed_reader/
builder.rs1use std::{
2 ffi::{OsStr, OsString},
3 fs::File,
4 io::{self, Read},
5 path::{Path, PathBuf},
6};
7
8use noodles_bgzf as bgzf;
9use noodles_csi::{self as csi, BinningIndex};
10
11use super::IndexedReader;
12use crate::bai;
13
14#[derive(Default)]
16pub struct Builder {
17 index: Option<Box<dyn BinningIndex>>,
18}
19
20impl Builder {
21 pub fn set_index<I>(mut self, index: I) -> Self
31 where
32 I: BinningIndex + 'static,
33 {
34 self.index = Some(Box::new(index));
35 self
36 }
37
38 pub fn build_from_path<P>(self, src: P) -> io::Result<IndexedReader<bgzf::io::Reader<File>>>
51 where
52 P: AsRef<Path>,
53 {
54 let src = src.as_ref();
55
56 let index = match self.index {
57 Some(index) => index,
58 None => read_associated_index(src)?,
59 };
60
61 let file = File::open(src)?;
62
63 Ok(IndexedReader::new(file, index))
64 }
65
66 pub fn build_from_reader<R>(self, reader: R) -> io::Result<IndexedReader<bgzf::io::Reader<R>>>
78 where
79 R: Read,
80 {
81 let index = self
82 .index
83 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "missing index"))?;
84
85 Ok(IndexedReader::new(reader, index))
86 }
87}
88
89fn read_associated_index<P>(src: P) -> io::Result<Box<dyn BinningIndex>>
90where
91 P: AsRef<Path>,
92{
93 let src = src.as_ref();
94
95 match bai::fs::read(build_index_src(src, "bai")) {
96 Ok(index) => Ok(Box::new(index)),
97 Err(e) if e.kind() == io::ErrorKind::NotFound => {
98 let index = csi::fs::read(build_index_src(src, "csi"))?;
99 Ok(Box::new(index))
100 }
101 Err(e) => Err(e),
102 }
103}
104
105fn build_index_src<P, S>(src: P, ext: S) -> PathBuf
106where
107 P: AsRef<Path>,
108 S: AsRef<OsStr>,
109{
110 push_ext(src.as_ref().into(), ext)
111}
112
113fn push_ext<S>(path: PathBuf, ext: S) -> PathBuf
114where
115 S: AsRef<OsStr>,
116{
117 let mut s = OsString::from(path);
118 s.push(".");
119 s.push(ext);
120 PathBuf::from(s)
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_push_ext() {
129 assert_eq!(
130 push_ext(PathBuf::from("sample.bam"), "bai"),
131 PathBuf::from("sample.bam.bai")
132 );
133 }
134}