noodles_sam/record.rs
1//! SAM record.
2
3mod cigar;
4pub mod data;
5pub mod fields;
6mod quality_scores;
7mod sequence;
8
9use std::{fmt, io};
10
11use bstr::BStr;
12use noodles_core::Position;
13
14pub(crate) use self::fields::Fields;
15pub use self::{cigar::Cigar, data::Data, quality_scores::QualityScores, sequence::Sequence};
16use crate::{
17 alignment::record::{Flags, MappingQuality},
18 Header,
19};
20
21/// A SAM record.
22#[derive(Clone, Default, Eq, PartialEq)]
23pub struct Record(Fields);
24
25impl Record {
26 #[cfg(test)]
27 pub(crate) fn fields(&self) -> &Fields {
28 &self.0
29 }
30
31 pub(crate) fn fields_mut(&mut self) -> &mut Fields {
32 &mut self.0
33 }
34
35 /// Returns the name.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// use noodles_sam as sam;
41 /// let record = sam::Record::default();
42 /// assert!(record.name().is_none());
43 /// ```
44 pub fn name(&self) -> Option<&BStr> {
45 self.0.name()
46 }
47
48 /// Returns the flags.
49 ///
50 /// # Examples
51 ///
52 /// ```
53 /// use noodles_sam::{self as sam, alignment::record::Flags};
54 /// let record = sam::Record::default();
55 /// assert_eq!(record.flags()?, Flags::UNMAPPED);
56 /// # Ok::<_, std::io::Error>(())
57 /// ```
58 pub fn flags(&self) -> io::Result<Flags> {
59 self.0.flags().map(Flags::from)
60 }
61
62 /// Returns the reference sequence ID.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// use noodles_sam as sam;
68 /// let header = sam::Header::default();
69 /// let record = sam::Record::default();
70 /// assert!(record.reference_sequence_id(&header).is_none());
71 /// ```
72 pub fn reference_sequence_id(&self, header: &Header) -> Option<io::Result<usize>> {
73 self.0.reference_sequence_id(header)
74 }
75
76 /// Returns the reference sequence name.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use noodles_sam as sam;
82 /// let record = sam::Record::default();
83 /// assert!(record.reference_sequence_name().is_none());
84 /// ```
85 pub fn reference_sequence_name(&self) -> Option<&BStr> {
86 self.0.reference_sequence_name()
87 }
88
89 /// Returns the alignment start.
90 ///
91 /// This position is 1-based, inclusive.
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// use noodles_sam as sam;
97 /// let record = sam::Record::default();
98 /// assert!(record.alignment_start().is_none());
99 /// # Ok::<_, std::io::Error>(())
100 /// ```
101 pub fn alignment_start(&self) -> Option<io::Result<Position>> {
102 self.0.alignment_start()
103 }
104
105 /// Returns the mapping quality.
106 ///
107 /// # Examples
108 ///
109 /// ```
110 /// use noodles_sam as sam;
111 /// let record = sam::Record::default();
112 /// assert!(record.mapping_quality().is_none());
113 /// ```
114 pub fn mapping_quality(&self) -> Option<io::Result<MappingQuality>> {
115 match self.0.mapping_quality().transpose() {
116 Ok(Some(n)) => MappingQuality::new(n).map(Ok),
117 Ok(None) => None,
118 Err(e) => Some(Err(e)),
119 }
120 }
121
122 /// Returns the CIGAR operations.
123 ///
124 /// # Examples
125 ///
126 /// ```
127 /// use noodles_sam as sam;
128 /// let record = sam::Record::default();
129 /// assert!(record.cigar().is_empty());
130 /// ```
131 pub fn cigar(&self) -> Cigar<'_> {
132 self.0.cigar()
133 }
134
135 /// Returns the mate reference sequence ID.
136 ///
137 /// # Examples
138 ///
139 /// ```
140 /// use noodles_sam as sam;
141 /// let header = sam::Header::default();
142 /// let record = sam::Record::default();
143 /// assert!(record.mate_reference_sequence_id(&header).is_none());
144 /// ```
145 pub fn mate_reference_sequence_id(&self, header: &Header) -> Option<io::Result<usize>> {
146 self.0.mate_reference_sequence_id(header)
147 }
148
149 /// Returns the mate reference sequence name.
150 ///
151 /// # Examples
152 ///
153 /// ```
154 /// use noodles_sam as sam;
155 /// let record = sam::Record::default();
156 /// assert!(record.mate_reference_sequence_name().is_none());
157 /// ```
158 pub fn mate_reference_sequence_name(&self) -> Option<&BStr> {
159 self.0.mate_reference_sequence_name()
160 }
161
162 /// Returns the mate alignment start.
163 ///
164 /// This position is 1-based, inclusive.
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// use noodles_sam as sam;
170 /// let record = sam::Record::default();
171 /// assert!(record.mate_alignment_start().is_none());
172 /// # Ok::<_, std::io::Error>(())
173 /// ```
174 pub fn mate_alignment_start(&self) -> Option<io::Result<Position>> {
175 self.0.mate_alignment_start()
176 }
177
178 /// Returns the template length.
179 ///
180 /// # Examples
181 ///
182 /// ```
183 /// use noodles_sam as sam;
184 /// let record = sam::Record::default();
185 /// assert_eq!(record.template_length()?, 0);
186 /// # Ok::<_, std::io::Error>(())
187 /// ```
188 pub fn template_length(&self) -> io::Result<i32> {
189 self.0.template_length()
190 }
191
192 /// Returns the sequence.
193 ///
194 /// # Examples
195 ///
196 /// ```
197 /// use noodles_sam as sam;
198 /// let record = sam::Record::default();
199 /// assert!(record.sequence().is_empty());
200 /// ```
201 pub fn sequence(&self) -> Sequence<'_> {
202 self.0.sequence()
203 }
204
205 /// Returns the quality scores.
206 ///
207 /// # Examples
208 ///
209 /// ```
210 /// use noodles_sam as sam;
211 /// let record = sam::Record::default();
212 /// assert!(record.quality_scores().is_empty());
213 /// ```
214 pub fn quality_scores(&self) -> QualityScores<'_> {
215 self.0.quality_scores()
216 }
217
218 /// Returns the data.
219 ///
220 /// # Examples
221 ///
222 /// ```
223 /// use noodles_sam as sam;
224 /// let record = sam::Record::default();
225 /// assert!(record.data().is_empty());
226 /// ```
227 pub fn data(&self) -> Data<'_> {
228 self.0.data()
229 }
230}
231
232impl fmt::Debug for Record {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 f.debug_struct("Record")
235 .field("name", &self.name())
236 .field("flags", &self.flags())
237 .field("reference_sequence_name", &self.reference_sequence_name())
238 .field("alignment_start", &self.alignment_start())
239 .field("mapping_quality", &self.mapping_quality())
240 .field("cigar", &self.cigar())
241 .field(
242 "mate_reference_sequence_name",
243 &self.mate_reference_sequence_name(),
244 )
245 .field("mate_alignment_start", &self.mate_alignment_start())
246 .field("template_length", &self.template_length())
247 .field("sequence", &self.sequence())
248 .field("quality_scores", &self.quality_scores())
249 .field("data", &self.data())
250 .finish()
251 }
252}
253
254impl TryFrom<&[u8]> for Record {
255 type Error = io::Error;
256
257 fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
258 use crate::io::Reader;
259
260 let mut reader = Reader::new(buf);
261 let mut record = Self::default();
262 reader.read_record(&mut record)?;
263 Ok(record)
264 }
265}
266
267impl crate::alignment::Record for Record {
268 fn name(&self) -> Option<&BStr> {
269 self.name()
270 }
271
272 fn flags(&self) -> io::Result<Flags> {
273 self.flags()
274 }
275
276 fn reference_sequence_id<'r, 'h: 'r>(
277 &'r self,
278 header: &'h Header,
279 ) -> Option<io::Result<usize>> {
280 self.reference_sequence_id(header)
281 }
282
283 fn alignment_start(&self) -> Option<io::Result<Position>> {
284 self.alignment_start()
285 }
286
287 fn mapping_quality(&self) -> Option<io::Result<MappingQuality>> {
288 self.mapping_quality()
289 }
290
291 fn cigar(&self) -> Box<dyn crate::alignment::record::Cigar + '_> {
292 Box::new(self.cigar())
293 }
294
295 fn mate_reference_sequence_id<'r, 'h: 'r>(
296 &'r self,
297 header: &'h Header,
298 ) -> Option<io::Result<usize>> {
299 self.mate_reference_sequence_id(header)
300 }
301
302 fn mate_alignment_start(&self) -> Option<io::Result<Position>> {
303 self.mate_alignment_start()
304 }
305
306 fn template_length(&self) -> io::Result<i32> {
307 self.template_length()
308 }
309
310 fn sequence(&self) -> Box<dyn crate::alignment::record::Sequence + '_> {
311 Box::new(self.sequence())
312 }
313
314 fn quality_scores(&self) -> Box<dyn crate::alignment::record::QualityScores + '_> {
315 Box::new(self.quality_scores())
316 }
317
318 fn data(&self) -> Box<dyn crate::alignment::record::Data + '_> {
319 Box::new(self.data())
320 }
321}