1use std::io::BufRead;
2use std::vec::IntoIter;
3
4use crate::BUF;
5
6pub struct FastqReader<R: BufRead> {
7 buf_reader: R,
8}
9
10impl<R: BufRead> FastqReader<R> {
11 pub fn new(inner: R) -> Self {
12 FastqReader {
13 buf_reader: inner
14 }
15 }
16
17 pub fn sequences(mut self) -> Option<FastqSequenceIterator<R>> {
18 let mut new_buffer = [0; BUF];
20 let new_bytes = self.buf_reader.read(&mut new_buffer).expect("error reading bytes from fastq file");
21
22 if new_bytes == 0 {return None}
24
25 Some(FastqSequenceIterator {
27 fastq_reader: self,
28 iter_buffer: new_buffer[..new_bytes].to_vec().into_iter(),
29 })
30 }
31}
32
33pub struct FastqSequenceIterator<R: BufRead> {
34 fastq_reader: FastqReader<R>,
35 iter_buffer: IntoIter<u8>,
36}
37
38impl<R: BufRead> Iterator for FastqSequenceIterator<R> {
39 type Item = Vec<u8>;
40
41 fn next(&mut self) -> Option<Self::Item> {
42
43 loop {
45 let mut is_rest = false;
46
47 let mut rest= Vec::new();
48
49 let mut name = Vec::new();
53 while !is_rest {
54 match self.iter_buffer.next() {
55 Some(10) => { rest.push(10); break },
56 None => is_rest = true,
57 Some(byte) => { rest.push(byte); name.push(byte) },
58 }
59 }
60
61 let mut sequence = Vec::new();
62 while !is_rest {
63 match self.iter_buffer.next() {
64 Some(10) => { rest.push(10); break },
65 None => is_rest = true,
66 Some(byte) => { rest.push(byte); sequence.push(byte) },
67 }
68 }
69
70 let mut plus = Vec::new();
71 while !is_rest {
72 match self.iter_buffer.next() {
73 Some(10) => { rest.push(10); break },
74 None => is_rest = true,
75 Some(byte) => { rest.push(byte); plus.push(byte) },
76 }
77 }
78
79 let mut quality = Vec::new();
80 while !is_rest {
81 match self.iter_buffer.next() {
82 Some(10) => { rest.push(10); break },
83 None => is_rest = true,
84 Some(byte) => { rest.push(byte); quality.push(byte) },
85 }
86 }
87
88 if !is_rest {
90 return Some(sequence);
91 }
92 else {
94 let mut vec_buffer = rest;
96
97 let mut new_buffer = [0; BUF];
98 let new_bytes = self.fastq_reader.buf_reader.read(&mut new_buffer).expect("error reading bytes from fastq file");
99
100 if new_bytes == 0 {
103 if vec_buffer.is_empty() { return None } else { panic!("error: finished reading fastq file with incomplete record in buffer") }
104 }
105
106 vec_buffer.append(&mut new_buffer[..new_bytes].to_vec());
108 self.iter_buffer = vec_buffer.into_iter();
109 }
110
111 }
112
113 }
114
115
116}
117
118#[cfg(test)]
119mod tests{
120 use std::fs::File;
121
122 use itertools::enumerate;
123
124 use super::FastqReader;
125
126 #[test]
127 fn test_read_sequence() {
128
129 let path = "test_data/test_100.fastq";
130 let reader = std::io::BufReader::new(File::open(path).expect("error opening fastq file"));
131 let fastq_reader = FastqReader::new(reader);
132
133 let compare_seqs = [
134 "CTTACATTCTTTAAATTCAGACTACTCTGTGTGCCGTTGTATAAGCTGTTCATCCATTGGTTTCAGTATTAATTTCCATTGGACTTATCTCCGTTTCGGACTTATTTTGCTTAAATAACGATTAAGCTTTCATTGGACTAACCACCAATTT".as_bytes(),
135 "GTCCGCATCACACCTTCGACTTATGCGGGGGTTTTTCCTCCCGCACATCTATTGTGCTTGCACCGGTTTTCTCATTCCCGGCTCTGTCTTACCTTCCGTGTCACTACAGTTCTGTTCATTACGGGTGCAGGAATCA".as_bytes(),
136 "CTCTTTAAGCTGGAGATAACGGTATTTTCACGAATGTTCAGGATGCCGAAGATACCGGTTGCTCTTCTCTCTTCTGTCAGAAGTGCAAATCCGTTCTTGATCGAATA".as_bytes(),
137 "CGACACTCCTTTATTTTCCTGAAAAACCATCTTTACAGGAACAGATAATTCCGAATCATTACCAATAGCATTTAATATCTCAATAGAATATGTATCAGTTGTGCCATCATCAACAATTATTATTCTTTTAGGCAATACTGTTTGATTACA".as_bytes(),
138 "CCATCTTCTTTCAGATCAACGCGGGTCAGGTGAGAGGTTTCCGGACGTTCGTCGCCGTCAATCTCTTCGTTGGCCTCTTTAGTGCGCCCGATCATCATCTCTTGATCGTGAACGCTCATACGGTTGAGTTGCTTCAGGTTGTGCTCCCAA".as_bytes(),
139 "CTTGACAATAATAACTTTGTATTACATTGGACTTATCTCCGTTCTTAAATTTGAATATAAAAGTCTTTTGACCGTTAAAATTCATAATATCAATCAGTACAAAGATTGCTTAAAAGCTTATCAACTTTTTCTCTGAATCAATTGTAC".as_bytes(),
140 "TGGGTTGTAAATATCGTCGATGATAACTGCGAAGGACGGATACAGAACCCAAGCAACGGTGTGCCATCCATACTGATCCATAACGGCTTTCTCGTTTGCTACTGCGTTCGGACCTGAACCACAACCCCATCCACAGTTACCAGCTGCCATA".as_bytes(),
141 "ATAAACGATATGATGTTTATCATTCGGTTTATTTAGAAGTTTGATAGATTGAAATTATAATTCACGTTTTATAATTTCTTCTGCAGAAATATCGGATATACTTCTCAGGCTCTGAATCATTATCATAAACAATTTCAAACTTAATTCGGTT".as_bytes(),
142 "GTCAGAATCATTAGTCTCATTAGTATATCCTACATTTTTCCCATAAATATGAGCAAAGACAACTCCGGGAACATTGCATTTTCTTGCATATAATGAAATTTGTCCCATGCGAATGAAAGGAATATCACTTGGTTTTTGATTTAGAAAATG".as_bytes(),
143 "GTTCTTGGGGTAATGGGTTTGATGCCGAGGACCAAAGCCTCTTAACTCTAGTACATTGGAGTATCTCCTTATGGATCAGGTGAAGTTCAGGTACATCCTGTTCGGCGGAGTGGTGACGGTCATCTCTACCAGCCTTCTTTA".as_bytes(),
144 ];
145
146 match fastq_reader.sequences() {
147 Some(seq_iter) => {
148 for (i, seq) in enumerate(seq_iter) {
149 assert_eq!(compare_seqs[i], seq);
150 }
151 },
152 None => panic!("error reading from fastq file")
153 }
154 }
155}
156