1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! FASTA writer.

mod builder;

pub use self::builder::Builder;

use std::io::{self, Write};

use super::{record::Sequence, Record};

/// A FASTA writer.
pub struct Writer<W> {
    inner: W,
    line_base_count: usize,
}

impl<W> Writer<W>
where
    W: Write,
{
    /// Creates a FASTA writer builder.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_fasta as fasta;
    /// let writer = fasta::Writer::builder(Vec::new()).build();
    /// ```
    pub fn builder(inner: W) -> Builder<W> {
        Builder::new(inner)
    }

    /// Creates a FASTA writer.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_fasta as fasta;
    /// let writer = fasta::Writer::new(Vec::new());
    /// ```
    pub fn new(inner: W) -> Self {
        Self::builder(inner).build()
    }

    /// Returns a reference to the underlying writer.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_fasta as fasta;
    /// let writer = fasta::Writer::new(Vec::new());
    /// assert!(writer.get_ref().is_empty());
    /// ```
    pub fn get_ref(&self) -> &W {
        &self.inner
    }

    /// Writes a FASTA record.
    ///
    /// Sequence lines are hard wrapped at 80 bases.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::io;
    /// use noodles_fasta::{self as fasta, record::{Definition, Sequence}};
    ///
    /// let mut writer = fasta::Writer::new(Vec::new());
    ///
    /// let definition = Definition::new("sq0", None);
    /// let sequence = Sequence::from(b"ACGT".to_vec());
    /// let record = fasta::Record::new(definition, sequence);
    ///
    /// writer.write_record(&record)?;
    ///
    /// assert_eq!(writer.get_ref(), b">sq0\nACGT\n");
    /// # Ok::<(), io::Error>(())
    /// ```
    pub fn write_record(&mut self, record: &Record) -> io::Result<()> {
        writeln!(self.inner, "{}", record.definition())?;
        write_record_sequence(&mut self.inner, record.sequence(), self.line_base_count)?;
        Ok(())
    }
}

fn write_record_sequence<W>(
    writer: &mut W,
    sequence: &Sequence,
    line_bases: usize,
) -> io::Result<()>
where
    W: Write,
{
    for bases in sequence.as_ref().chunks(line_bases) {
        writer.write_all(bases)?;
        writeln!(writer)?;
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_new() {
        let writer = Writer::new(Vec::new());
        assert_eq!(writer.line_base_count, 80);
    }

    #[test]
    fn test_write_record_sequence() -> io::Result<()> {
        let mut writer = Vec::new();
        let sequence = Sequence::from(b"AC".to_vec());
        write_record_sequence(&mut writer, &sequence, 4)?;
        assert_eq!(writer, b"AC\n");

        writer.clear();
        let sequence = Sequence::from(b"ACGT".to_vec());
        write_record_sequence(&mut writer, &sequence, 4)?;
        assert_eq!(writer, b"ACGT\n");

        writer.clear();
        let sequence = Sequence::from(b"ACGTACGT".to_vec());
        write_record_sequence(&mut writer, &sequence, 4)?;
        assert_eq!(writer, b"ACGT\nACGT\n");

        writer.clear();
        let sequence = Sequence::from(b"ACGTACGTAC".to_vec());
        write_record_sequence(&mut writer, &sequence, 4)?;
        assert_eq!(writer, b"ACGT\nACGT\nAC\n");

        Ok(())
    }
}