noodles_fasta/io/indexed_reader/
builder.rs1use std::{
2 ffi::{OsStr, OsString},
3 fs::File,
4 io::{self, BufRead, BufReader},
5 path::{Path, PathBuf},
6};
7
8use noodles_bgzf as bgzf;
9
10use super::IndexedReader;
11use crate::fai;
12
13#[derive(Default)]
15pub struct Builder {
16 index: Option<fai::Index>,
17}
18
19impl Builder {
20 pub fn set_index(mut self, index: fai::Index) -> Self {
30 self.index = Some(index);
31 self
32 }
33
34 pub fn build_from_path<P>(self, src: P) -> io::Result<IndexedReader<crate::io::BufReader<File>>>
44 where
45 P: AsRef<Path>,
46 {
47 let src = src.as_ref();
48
49 let index = match self.index {
50 Some(index) => index,
51 None => {
52 let index_src = build_index_src(src);
53 fai::fs::read(index_src)?
54 }
55 };
56
57 let reader = match src.extension().and_then(|ext| ext.to_str()) {
58 Some("gz" | "bgz") => bgzf::indexed_reader::Builder::default()
59 .build_from_path(src)
60 .map(crate::io::BufReader::Bgzf)?,
61 _ => File::open(src)
62 .map(BufReader::new)
63 .map(crate::io::BufReader::Uncompressed)?,
64 };
65
66 Ok(IndexedReader::new(reader, index))
67 }
68
69 pub fn build_from_reader<R>(self, reader: R) -> io::Result<IndexedReader<R>>
84 where
85 R: BufRead,
86 {
87 let index = self
88 .index
89 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "missing index"))?;
90
91 Ok(IndexedReader::new(reader, index))
92 }
93}
94
95fn build_index_src<P>(src: P) -> PathBuf
96where
97 P: AsRef<Path>,
98{
99 const EXT: &str = "fai";
100 push_ext(src.as_ref().into(), EXT)
101}
102
103fn push_ext<S>(path: PathBuf, ext: S) -> PathBuf
104where
105 S: AsRef<OsStr>,
106{
107 let mut s = OsString::from(path);
108 s.push(".");
109 s.push(ext);
110 PathBuf::from(s)
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_build_index_src() {
119 assert_eq!(build_index_src("ref.fa"), PathBuf::from("ref.fa.fai"));
120 }
121}