noodles_fasta/async/io/
reader.rs

1mod sequence;
2
3use tokio::io::{
4    self, AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncSeek, AsyncSeekExt, SeekFrom,
5};
6
7use self::sequence::read_sequence;
8
9/// An async FASTA reader.
10pub struct Reader<R> {
11    inner: R,
12}
13
14impl<R> Reader<R> {
15    /// Returns a reference to the underlying reader.
16    ///
17    /// # Examples
18    ///
19    /// ```
20    /// use noodles_fasta as fasta;
21    /// use tokio::io;
22    /// let reader = fasta::r#async::io::Reader::new(io::empty());
23    /// let _inner = reader.get_ref();
24    /// ```
25    pub fn get_ref(&self) -> &R {
26        &self.inner
27    }
28
29    /// Returns a mutable reference to the underlying reader.
30    ///
31    /// # Examples
32    ///
33    /// ```
34    /// use noodles_fasta as fasta;
35    /// use tokio::io;
36    /// let mut reader = fasta::r#async::io::Reader::new(io::empty());
37    /// let _inner = reader.get_mut();
38    /// ```
39    pub fn get_mut(&mut self) -> &mut R {
40        &mut self.inner
41    }
42
43    /// Returns the underlying reader.
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// use noodles_fasta as fasta;
49    /// use tokio::io;
50    /// let reader = fasta::r#async::io::Reader::new(io::empty());
51    /// let _inner = reader.into_inner();
52    /// ```
53    pub fn into_inner(self) -> R {
54        self.inner
55    }
56}
57
58impl<R> Reader<R>
59where
60    R: AsyncBufRead + Unpin,
61{
62    /// Creates an async FASTA reader.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use noodles_fasta as fasta;
68    /// let data = [];
69    /// let mut reader = fasta::r#async::io::Reader::new(&data[..]);
70    /// ```
71    pub fn new(inner: R) -> Self {
72        Self { inner }
73    }
74
75    /// Reads a raw definition line.
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// # use std::io;
81    /// #
82    /// # #[tokio::main]
83    /// # async fn main() -> io::Result<()> {
84    /// use noodles_fasta as fasta;
85    ///
86    /// let data = b">sq0\nACGT\n>sq1\nNNNN\nNNNN\nNN\n";
87    /// let mut reader = fasta::r#async::io::Reader::new(&data[..]);
88    ///
89    /// let mut buf = String::new();
90    /// reader.read_definition(&mut buf).await?;
91    ///
92    /// assert_eq!(buf, ">sq0");
93    /// # Ok(())
94    /// # }
95    /// ```
96    pub async fn read_definition(&mut self, buf: &mut String) -> io::Result<usize> {
97        read_line(&mut self.inner, buf).await
98    }
99
100    /// Reads a sequence.
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// # use std::io;
106    /// #
107    /// # #[tokio::main]
108    /// # async fn main() -> io::Result<()> {
109    /// use noodles_fasta as fasta;
110    ///
111    /// let data = b">sq0\nACGT\n>sq1\nNNNN\nNNNN\nNN\n";
112    /// let mut reader = fasta::r#async::io::Reader::new(&data[..]);
113    /// reader.read_definition(&mut String::new()).await?;
114    ///
115    /// let mut buf = Vec::new();
116    /// reader.read_sequence(&mut buf).await?;
117    ///
118    /// assert_eq!(buf, b"ACGT");
119    /// # Ok(())
120    /// # }
121    /// ```
122    pub async fn read_sequence(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
123        read_sequence(&mut self.inner, buf).await
124    }
125}
126
127impl<R> Reader<R>
128where
129    R: AsyncRead + AsyncSeek + Unpin,
130{
131    /// Seeks the underlying stream to the given position.
132    pub async fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
133        self.inner.seek(pos).await
134    }
135}
136
137pub(crate) async fn read_line<R>(reader: &mut R, buf: &mut String) -> io::Result<usize>
138where
139    R: AsyncBufRead + Unpin,
140{
141    const LINE_FEED: char = '\n';
142    const CARRIAGE_RETURN: char = '\r';
143
144    match reader.read_line(buf).await? {
145        0 => Ok(0),
146        n => {
147            if buf.ends_with(LINE_FEED) {
148                buf.pop();
149
150                if buf.ends_with(CARRIAGE_RETURN) {
151                    buf.pop();
152                }
153            }
154
155            Ok(n)
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[tokio::test]
165    async fn test_read_definition() -> io::Result<()> {
166        let data = b">sq0\nACGT\n";
167        let mut reader = Reader::new(&data[..]);
168
169        let mut buf = String::new();
170        reader.read_definition(&mut buf).await?;
171
172        assert_eq!(buf, ">sq0");
173
174        Ok(())
175    }
176
177    #[tokio::test]
178    async fn test_read_line() -> io::Result<()> {
179        async fn t(buf: &mut String, mut data: &[u8], expected: &str) -> io::Result<()> {
180            buf.clear();
181            read_line(&mut data, buf).await?;
182            assert_eq!(buf, expected);
183            Ok(())
184        }
185
186        let mut buf = String::new();
187
188        t(&mut buf, b"noodles\n", "noodles").await?;
189        t(&mut buf, b"noodles\r\n", "noodles").await?;
190        t(&mut buf, b"noodles", "noodles").await?;
191
192        Ok(())
193    }
194}