Skip to main content

debruijn/
fastq.rs

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        // read into buffer
19        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        // return none if there is nothing in the file
23        if new_bytes == 0 {return None}
24
25        // turn buffer into iterator
26        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        // take        
44        loop {
45            let mut is_rest = false;
46
47            let mut rest= Vec::new();
48            
49            // return read seq, take iterator and rest as &mut
50            // TODO move loops to function, is repetetive
51            // 10 = ASCII character for newline
52            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            // full fastq record was found, return sequence
89            if !is_rest {
90                return Some(sequence);
91            }
92            // regular buffer is empty and needs to be filled, process needs to be repeated until a full record with a sequence is found
93            else {
94                // read new bytes
95                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                // return None if no new bytes were read
101                // TODO implement Error if there is still something in rest buffer
102                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                // append new buffer to rest from last round
107                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