noodles_cram/crai/io/
writer.rs

1use std::io::{self, Write};
2
3use flate2::write::GzEncoder;
4
5use crate::crai::Record;
6
7/// A CRAM index writer.
8pub struct Writer<W>
9where
10    W: Write,
11{
12    inner: GzEncoder<W>,
13}
14
15impl<W> Writer<W>
16where
17    W: Write,
18{
19    /// Creates a CRAM index writer.
20    ///
21    /// # Examples
22    ///
23    /// ```
24    /// use noodles_cram::crai;
25    /// let writer = crai::io::Writer::new(Vec::new());
26    /// ```
27    pub fn new(inner: W) -> Self {
28        Self {
29            inner: GzEncoder::new(inner, Default::default()),
30        }
31    }
32
33    /// Returns a reference to the underlying writer.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// use noodles_cram::crai;
39    /// let writer = crai::io::Writer::new(Vec::new());
40    /// assert!(writer.get_ref().is_empty());
41    /// ```
42    pub fn get_ref(&self) -> &W {
43        self.inner.get_ref()
44    }
45
46    /// Attempts to finish the output stream and returns the underlying writer.
47    ///
48    /// This is typically only manually called if the underlying stream is needed before the writer
49    /// is dropped.
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// # use std::io;
55    /// use noodles_cram::crai;
56    /// let writer = crai::io::Writer::new(Vec::new());
57    /// let empty_gz = [31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0];
58    /// assert_eq!(writer.finish()?, empty_gz);
59    /// # Ok::<(), io::Error>(())
60    /// ```
61    pub fn finish(self) -> io::Result<W> {
62        self.inner.finish()
63    }
64
65    /// Writes a CRAM index.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use noodles_core::Position;
71    /// use noodles_cram::crai;
72    ///
73    /// let mut writer = crai::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)?;
85    /// # Ok::<(), Box<dyn std::error::Error>>(())
86    /// ```
87    pub fn write_index(&mut self, index: &[Record]) -> io::Result<()> {
88        write_index(&mut self.inner, index)
89    }
90}
91
92fn write_index<W>(writer: &mut W, index: &[Record]) -> io::Result<()>
93where
94    W: Write,
95{
96    for record in index {
97        write_record(writer, record)?;
98    }
99
100    Ok(())
101}
102
103fn write_record<W>(writer: &mut W, record: &Record) -> io::Result<()>
104where
105    W: Write,
106{
107    writeln!(writer, "{record}")
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_write_record() -> Result<(), Box<dyn std::error::Error>> {
116        use noodles_core::Position;
117
118        let index = vec![Record::new(
119            Some(0),
120            Position::new(10946),
121            6765,
122            17711,
123            233,
124            317811,
125        )];
126
127        let mut buf = Vec::new();
128        write_index(&mut buf, &index)?;
129
130        let expected = b"0\t10946\t6765\t17711\t233\t317811\n";
131
132        assert_eq!(buf, expected);
133
134        Ok(())
135    }
136}