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}