noodles_vcf/io/
writer.rs

1//! VCF writer.
2
3mod builder;
4mod header;
5mod record;
6
7use std::io::{self, Write};
8
9pub use self::builder::Builder;
10use self::{header::write_header, record::write_record};
11use crate::{Header, Record};
12
13/// A VCF writer.
14///
15/// # Examples
16///
17/// ```
18/// # use std::io;
19/// use noodles_core::Position;
20/// use noodles_vcf::{
21///     self as vcf,
22///     header::{
23///         record::value::{map::Contig, Map},
24///         FileFormat,
25///     },
26///     variant::io::Write,
27/// };
28///
29/// let mut writer = vcf::io::Writer::new(Vec::new());
30///
31/// let header = vcf::Header::builder()
32///     .set_file_format(FileFormat::new(4, 5))
33///     .add_contig("sq0", Map::<Contig>::new())
34///     .build();
35///
36/// writer.write_header(&header)?;
37///
38/// let record = vcf::variant::RecordBuf::builder()
39///     .set_reference_sequence_name("sq0")
40///     .set_variant_start(Position::MIN)
41///     .set_reference_bases("A")
42///     .build();
43///
44/// writer.write_variant_record(&header, &record);
45///
46/// let expected = b"##fileformat=VCFv4.5
47/// ###contig=<ID=sq0>
48/// #CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO
49/// sq0\t1\t.\tA\t.\t.\t.\t.
50/// ";
51///
52/// assert_eq!(&writer.get_ref()[..], &expected[..]);
53/// # Ok::<_, std::io::Error>(())
54/// ```
55#[derive(Debug)]
56pub struct Writer<W> {
57    inner: W,
58}
59
60impl<W> Writer<W>
61where
62    W: Write,
63{
64    /// Creates a VCF writer.
65    ///
66    /// # Examples
67    ///
68    /// ```
69    /// use noodles_vcf as vcf;
70    /// let writer = vcf::io::Writer::new(Vec::new());
71    /// ```
72    pub fn new(inner: W) -> Self {
73        Self { inner }
74    }
75
76    /// Returns a reference to the underlying writer.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use noodles_vcf as vcf;
82    /// let writer = vcf::io::Writer::new(Vec::new());
83    /// assert!(writer.get_ref().is_empty());
84    /// ```
85    pub fn get_ref(&self) -> &W {
86        &self.inner
87    }
88
89    /// Returns a mutable reference to the underlying writer.
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use noodles_vcf as vcf;
95    /// let mut writer = vcf::io::Writer::new(Vec::new());
96    /// assert!(writer.get_mut().is_empty());
97    /// ```
98    pub fn get_mut(&mut self) -> &mut W {
99        &mut self.inner
100    }
101
102    /// Unwraps and returns the underlying writer.
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// use noodles_vcf as vcf;
108    /// let writer = vcf::io::Writer::new(Vec::new());
109    /// assert!(writer.into_inner().is_empty());
110    /// ```
111    pub fn into_inner(self) -> W {
112        self.inner
113    }
114
115    /// Writes a VCF header.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// # use std::io;
121    /// use noodles_vcf as vcf;
122    ///
123    /// let mut writer = vcf::io::Writer::new(Vec::new());
124    ///
125    /// let header = vcf::Header::default();
126    /// writer.write_header(&header)?;
127    /// # Ok::<(), io::Error>(())
128    /// ```
129    pub fn write_header(&mut self, header: &Header) -> io::Result<()> {
130        write_header(&mut self.inner, header)
131    }
132
133    /// Writes a VCF record.
134    ///
135    /// # Examples
136    ///
137    /// ```
138    /// use noodles_core::Position;
139    /// use noodles_vcf as vcf;
140    ///
141    /// let mut writer = vcf::io::Writer::new(Vec::new());
142    ///
143    /// let header = vcf::Header::default();
144    /// let record = vcf::Record::default();
145    /// writer.write_record(&header, &record)?;
146    ///
147    /// assert_eq!(writer.get_ref(), b"sq0\t1\t.\tA\t.\t.\t.\t.\n");
148    /// # Ok::<_, std::io::Error>(())
149    /// ```
150    pub fn write_record(&mut self, header: &Header, record: &Record) -> io::Result<()> {
151        write_record(&mut self.inner, header, record)
152    }
153}
154
155impl<W> crate::variant::io::Write for Writer<W>
156where
157    W: Write,
158{
159    fn write_variant_header(&mut self, header: &Header) -> io::Result<()> {
160        self.write_header(header)
161    }
162
163    fn write_variant_record(
164        &mut self,
165        header: &Header,
166        record: &dyn crate::variant::Record,
167    ) -> io::Result<()> {
168        write_record(&mut self.inner, header, record)
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use noodles_core::Position;
175
176    use super::*;
177    use crate::variant::{io::Write, RecordBuf};
178
179    #[test]
180    fn test_write_variant_record() -> io::Result<()> {
181        let header = Header::default();
182
183        let record = RecordBuf::builder()
184            .set_reference_sequence_name("sq0")
185            .set_variant_start(Position::MIN)
186            .set_reference_bases("A")
187            .build();
188
189        let mut writer = Writer::new(Vec::new());
190        writer.write_variant_record(&header, &record)?;
191
192        let expected = b"sq0\t1\t.\tA\t.\t.\t.\t.\n";
193        assert_eq!(writer.get_ref(), expected);
194
195        Ok(())
196    }
197
198    #[test]
199    fn test_write_record_with_format() -> Result<(), Box<dyn std::error::Error>> {
200        use crate::variant::{
201            record::samples::keys::key,
202            record_buf::{samples::sample::Value, Samples},
203        };
204
205        let header = Header::default();
206
207        let samples = Samples::new(
208            [
209                String::from(key::GENOTYPE),
210                String::from(key::CONDITIONAL_GENOTYPE_QUALITY),
211            ]
212            .into_iter()
213            .collect(),
214            vec![vec![
215                Some(Value::String(String::from("0|0"))),
216                Some(Value::Integer(13)),
217            ]],
218        );
219
220        let record = RecordBuf::builder()
221            .set_reference_sequence_name("sq0")
222            .set_variant_start(Position::MIN)
223            .set_reference_bases("A")
224            .set_samples(samples)
225            .build();
226
227        let mut writer = Writer::new(Vec::new());
228        writer.write_variant_record(&header, &record)?;
229
230        let expected = b"sq0\t1\t.\tA\t.\t.\t.\t.\tGT:GQ\t0|0:13\n";
231        assert_eq!(writer.get_ref(), expected);
232
233        Ok(())
234    }
235}