noodles_sam/io/writer/
record.rs1mod cigar;
4mod data;
5mod flags;
6mod mapping_quality;
7mod name;
8mod position;
9mod quality_scores;
10mod reference_sequence_name;
11mod sequence;
12mod template_length;
13
14use std::io::{self, Write};
15
16pub use self::cigar::write_cigar;
17use self::{
18 data::write_data,
19 flags::write_flags,
20 mapping_quality::write_mapping_quality,
21 name::write_name,
22 position::write_position,
23 quality_scores::write_quality_scores,
24 reference_sequence_name::{write_mate_reference_sequence_name, write_reference_sequence_name},
25 sequence::write_sequence,
26 template_length::write_template_length,
27};
28use crate::{alignment::Record, Header};
29
30const MISSING: u8 = b'*';
31
32pub(crate) fn write_record<W, R>(writer: &mut W, header: &Header, record: &R) -> io::Result<()>
33where
34 W: Write,
35 R: Record + ?Sized,
36{
37 const DELIMITER: &[u8] = b"\t";
38
39 write_name(writer, record.name())?;
40
41 writer.write_all(DELIMITER)?;
42 let flags = record.flags()?;
43 write_flags(writer, flags)?;
44
45 writer.write_all(DELIMITER)?;
46
47 let reference_sequence_name = record
48 .reference_sequence(header)
49 .transpose()?
50 .map(|(name, _)| name.as_ref());
51
52 write_reference_sequence_name(writer, reference_sequence_name)?;
53
54 writer.write_all(DELIMITER)?;
55 let alignment_start = record.alignment_start().transpose()?;
56 write_position(writer, alignment_start)?;
57
58 writer.write_all(DELIMITER)?;
59 let mapping_quality = record.mapping_quality().transpose()?;
60 write_mapping_quality(writer, mapping_quality)?;
61
62 let cigar = record.cigar();
63
64 writer.write_all(DELIMITER)?;
65 write_cigar(writer, &cigar)?;
66
67 writer.write_all(DELIMITER)?;
68
69 let mate_reference_sequence_name = record
70 .mate_reference_sequence(header)
71 .transpose()?
72 .map(|(name, _)| name.as_ref());
73
74 write_mate_reference_sequence_name(
75 writer,
76 reference_sequence_name,
77 mate_reference_sequence_name,
78 )?;
79
80 writer.write_all(DELIMITER)?;
81 let mate_alignment_start = record.mate_alignment_start().transpose()?;
82 write_position(writer, mate_alignment_start)?;
83
84 writer.write_all(DELIMITER)?;
85 let template_length = record.template_length()?;
86 write_template_length(writer, template_length)?;
87
88 let sequence = record.sequence();
89 let base_count = sequence.len();
90
91 writer.write_all(DELIMITER)?;
92 let read_length = cigar.read_length()?;
93 write_sequence(writer, read_length, sequence)?;
94
95 writer.write_all(DELIMITER)?;
96 write_quality_scores(writer, base_count, record.quality_scores())?;
97
98 write_data(writer, record.data())?;
99
100 writeln!(writer)?;
101
102 Ok(())
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::alignment::RecordBuf;
109
110 #[test]
111 fn test_write_record_with_data() -> io::Result<()> {
112 use crate::alignment::{record::data::field::Tag, record_buf::data::field::Value};
113
114 let mut buf = Vec::new();
115
116 let header = Header::default();
117
118 let data = [(Tag::READ_GROUP, Value::from("rg0"))]
119 .into_iter()
120 .collect();
121 let record = RecordBuf::builder().set_data(data).build();
122
123 write_record(&mut buf, &header, &record)?;
124
125 let expected = b"*\t4\t*\t0\t255\t*\t*\t0\t0\t*\t*\tRG:Z:rg0\n";
126 assert_eq!(buf, expected);
127
128 Ok(())
129 }
130}