Skip to main content

deepbiop_fq/encode/
traits.rs

1use anyhow::Result;
2use log::info;
3use needletail::Sequence;
4use noodles::fastq;
5use rayon::prelude::*;
6use std::{
7    io::BufReader,
8    path::{Path, PathBuf},
9};
10
11use crate::types::Element;
12use deepbiop_utils as utils;
13
14use super::RecordData;
15
16pub trait Encoder {
17    type EncodeOutput;
18    type RecordOutput;
19
20    fn encode_multiple(&mut self, paths: &[PathBuf], parallel: bool) -> Self::EncodeOutput;
21
22    fn encode<P: AsRef<Path>>(&mut self, path: P) -> Self::EncodeOutput;
23
24    fn encode_record(&self, id: &[u8], seq: &[u8], qual: &[u8]) -> Self::RecordOutput;
25
26    fn fetch_records<P: AsRef<Path>>(&mut self, path: P) -> Result<Vec<RecordData>> {
27        info!("fetching records from {}", path.as_ref().display());
28
29        let reader = utils::io::create_reader_for_compressed_file(path)?;
30        let mut reader = fastq::io::Reader::new(BufReader::new(reader));
31
32        let records: Vec<RecordData> = reader
33            .records()
34            .filter_map(|record| {
35                let record = record.ok()?;
36
37                let id = record.definition().name();
38                let seq = record.sequence();
39                let normalized_seq = seq.normalize(false);
40                let qual = record.quality_scores();
41                let seq_len = normalized_seq.len();
42                let qual_len = qual.len();
43
44                if seq_len != qual_len {
45                    // NOTE: it seems like log mes does not work well with rayon parallel iterator  <02-26-24, Yangyang Li>
46                    // warn!(
47                    //     "record: id {} seq_len != qual_len",
48                    //     String::from_utf8_lossy(id)
49                    // );
50                    return None;
51                }
52
53                Some((id.to_vec(), seq.to_vec(), qual.to_vec()).into())
54            })
55            .collect();
56        info!("total records: {}", records.len());
57        Ok(records)
58    }
59
60    fn encode_qual(&self, qual: &[u8], qual_offset: u8) -> Vec<Element> {
61        // input is quality of fastq
62        // 1. convert the quality to a score
63        // 2. return the score
64        let encoded_qual: Vec<u8> = qual
65            .par_iter()
66            .map(|&q| {
67                // Convert ASCII to Phred score for Phred+33 encoding
68                q - qual_offset
69            })
70            .collect();
71        encoded_qual.into_par_iter().map(|x| x as Element).collect()
72    }
73
74    fn encoder_seq<'a>(&self, seq: &'a [u8]) -> Result<&'a [u8]> {
75        Ok(seq)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81
82    use super::*;
83
84    #[test]
85    fn test_parse_target_from_id() {
86        // Test case 1: Valid input
87        #[allow(dead_code)]
88        struct TestEncoder;
89        impl Encoder for TestEncoder {
90            type RecordOutput = Result<RecordData>;
91            type EncodeOutput = Result<Vec<RecordData>>;
92
93            fn encode_multiple(
94                &mut self,
95                _paths: &[PathBuf],
96                _parallel: bool,
97            ) -> Self::EncodeOutput {
98                Ok(Vec::new())
99            }
100            fn encode<P: AsRef<Path>>(&mut self, _path: P) -> Self::EncodeOutput {
101                Ok(Vec::new())
102            }
103            fn encode_record(&self, _id: &[u8], _seq: &[u8], _qual: &[u8]) -> Self::RecordOutput {
104                Ok(RecordData::default())
105            }
106        }
107    }
108}