noodles_vcf/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};
10use noodles_tabix as tabix;
11
12use super::IndexedReader;
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
33 where
34 I: BinningIndex + 'static,
35 {
36 self.index = Some(Box::new(index));
37 self
38 }
39
40 pub fn build_from_path<P>(self, src: P) -> io::Result<IndexedReader<bgzf::Reader<File>>>
50 where
51 P: AsRef<Path>,
52 {
53 let src = src.as_ref();
54
55 let index = match self.index {
56 Some(index) => index,
57 None => read_associated_index(src)?,
58 };
59
60 let file = File::open(src)?;
61
62 Ok(IndexedReader::new(file, index))
63 }
64
65 pub fn build_from_reader<R>(self, reader: R) -> io::Result<IndexedReader<bgzf::Reader<R>>>
81 where
82 R: Read,
83 {
84 let index = self
85 .index
86 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "missing index"))?;
87
88 Ok(IndexedReader::new(reader, index))
89 }
90}
91
92fn read_associated_index<P>(src: P) -> io::Result<Box<dyn BinningIndex>>
93where
94 P: AsRef<Path>,
95{
96 let src = src.as_ref();
97
98 match tabix::fs::read(build_index_src(src, "tbi")) {
99 Ok(index) => Ok(Box::new(index)),
100 Err(e) if e.kind() == io::ErrorKind::NotFound => {
101 let index = csi::fs::read(build_index_src(src, "csi"))?;
102 Ok(Box::new(index))
103 }
104 Err(e) => Err(e),
105 }
106}
107
108fn build_index_src<P, S>(src: P, ext: S) -> PathBuf
109where
110 P: AsRef<Path>,
111 S: AsRef<OsStr>,
112{
113 push_ext(src.as_ref().into(), ext)
114}
115
116fn push_ext<S>(path: PathBuf, ext: S) -> PathBuf
117where
118 S: AsRef<OsStr>,
119{
120 let mut s = OsString::from(path);
121 s.push(".");
122 s.push(ext);
123 PathBuf::from(s)
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_push_ext() {
132 assert_eq!(
133 push_ext(PathBuf::from("sample.vcf.gz"), "tbi"),
134 PathBuf::from("sample.vcf.gz.tbi")
135 );
136 }
137}