noodles_cram/crai/async/io/writer.rs
1use async_compression::tokio::write::GzipEncoder;
2use tokio::io::{self, AsyncWrite, AsyncWriteExt};
3
4use crate::crai::Record;
5
6/// An async CRAM index writer.
7pub struct Writer<W> {
8 inner: GzipEncoder<W>,
9}
10
11impl<W> Writer<W>
12where
13 W: AsyncWrite + Unpin,
14{
15 /// Creates an async CRAM index writer.
16 ///
17 /// # Examples
18 ///
19 /// ```
20 /// use noodles_cram::crai;
21 /// let writer = crai::r#async::io::Writer::new(Vec::new());
22 /// ```
23 pub fn new(inner: W) -> Self {
24 Self {
25 inner: GzipEncoder::new(inner),
26 }
27 }
28
29 /// Returns the underlying writer.
30 ///
31 /// # Examples
32 ///
33 /// ```
34 /// use noodles_cram::crai;
35 /// let writer = crai::r#async::io::Writer::new(Vec::new());
36 /// assert!(writer.into_inner().is_empty());
37 /// ```
38 pub fn into_inner(self) -> W {
39 self.inner.into_inner()
40 }
41
42 /// Shuts down the output stream.
43 ///
44 /// # Examples
45 ///
46 /// ```
47 /// # use std::io;
48 /// #
49 /// # #[tokio::main]
50 /// # async fn main() -> io::Result<()> {
51 /// use noodles_cram::crai;
52 /// let mut writer = crai::r#async::io::Writer::new(Vec::new());
53 /// writer.shutdown().await?;
54 /// # Ok(())
55 /// # }
56 /// ```
57 pub async fn shutdown(&mut self) -> io::Result<()> {
58 self.inner.shutdown().await
59 }
60
61 /// Writes a CRAM index.
62 ///
63 /// # Examples
64 ///
65 /// ```
66 /// # use std::io;
67 /// #
68 /// # #[tokio::main]
69 /// # async fn main() -> io::Result<()> {
70 /// use noodles_core::Position;
71 /// use noodles_cram::crai;
72 ///
73 /// let mut writer = crai::r#async::io::Writer::new(Vec::new());
74 ///
75 /// let index = vec![crai::Record::new(
76 /// Some(0),
77 /// Position::new(10946),
78 /// 6765,
79 /// 17711,
80 /// 233,
81 /// 317811,
82 /// )];
83 ///
84 /// writer.write_index(&index).await?;
85 /// # Ok(())
86 /// # }
87 /// ```
88 pub async fn write_index(&mut self, index: &[Record]) -> io::Result<()> {
89 write_index(&mut self.inner, index).await
90 }
91}
92
93async fn write_index<W>(writer: &mut W, index: &[Record]) -> io::Result<()>
94where
95 W: AsyncWrite + Unpin,
96{
97 for record in index {
98 write_record(writer, record).await?;
99 }
100
101 Ok(())
102}
103
104async fn write_record<W>(writer: &mut W, record: &Record) -> io::Result<()>
105where
106 W: AsyncWrite + Unpin,
107{
108 const LINE_FEED: u8 = b'\n';
109
110 writer.write_all(record.to_string().as_bytes()).await?;
111 writer.write_all(&[LINE_FEED]).await?;
112 Ok(())
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[tokio::test]
120 async fn test_write_record() -> Result<(), Box<dyn std::error::Error>> {
121 use noodles_core::Position;
122
123 let mut buf = Vec::new();
124
125 let record = Record::new(Some(0), Position::new(10946), 6765, 17711, 233, 317811);
126 write_record(&mut buf, &record).await?;
127
128 let expected = b"0\t10946\t6765\t17711\t233\t317811\n";
129 assert_eq!(buf, expected);
130
131 Ok(())
132 }
133}