noodles_cram/crai/io/
reader.rs1use std::io::{self, BufRead, BufReader, Read};
2
3use flate2::read::GzDecoder;
4
5use crate::crai::Index;
6
7pub struct Reader<R> {
9 inner: BufReader<GzDecoder<R>>,
10}
11
12impl<R> Reader<R>
13where
14 R: Read,
15{
16 pub fn new(inner: R) -> Self {
26 Self {
27 inner: BufReader::new(GzDecoder::new(inner)),
28 }
29 }
30
31 pub fn read_index(&mut self) -> io::Result<Index> {
45 let mut buf = String::new();
46 let mut index = Vec::new();
47
48 loop {
49 buf.clear();
50
51 match read_line(&mut self.inner, &mut buf) {
52 Ok(0) => break,
53 Ok(_) => {
54 let record = buf
55 .parse()
56 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
57
58 index.push(record);
59 }
60 Err(e) => return Err(e),
61 }
62 }
63
64 Ok(index)
65 }
66}
67
68fn read_line<R>(reader: &mut R, buf: &mut String) -> io::Result<usize>
69where
70 R: BufRead,
71{
72 match reader.read_line(buf) {
73 Ok(0) => Ok(0),
74 Ok(n) => {
75 buf.pop();
76 Ok(n)
77 }
78 Err(e) => Err(e),
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use std::io::Write;
85
86 use flate2::write::GzEncoder;
87 use noodles_core::Position;
88
89 use crate::crai::Record;
90
91 use super::*;
92
93 #[test]
94 fn test_read_index() -> Result<(), Box<dyn std::error::Error>> {
95 let data = b"\
960\t10946\t6765\t17711\t233\t317811
970\t17711\t121393\t317811\t233\t317811
98";
99
100 let mut writer = GzEncoder::new(Vec::new(), Default::default());
101 writer.write_all(data)?;
102 let compressed_data = writer.finish()?;
103
104 let mut reader = Reader::new(&compressed_data[..]);
105
106 let actual = reader.read_index()?;
107
108 let expected = vec![
109 Record::new(Some(0), Position::new(10946), 6765, 17711, 233, 317811),
110 Record::new(Some(0), Position::new(17711), 121393, 317811, 233, 317811),
111 ];
112
113 assert_eq!(actual, expected);
114
115 Ok(())
116 }
117}