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}