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}