noodles_sam/record/
data.rs

1//! SAM record data and fields.
2
3pub mod field;
4
5use std::{fmt, io, iter};
6
7use self::field::parse_field;
8use crate::alignment::record::data::field::{Tag, Value};
9
10/// Raw SAM record data.
11pub struct Data<'a>(&'a [u8]);
12
13impl<'a> Data<'a> {
14    pub(super) fn new(buf: &'a [u8]) -> Self {
15        Self(buf)
16    }
17
18    /// Returns whether there are any data fields.
19    pub fn is_empty(&self) -> bool {
20        self.0.is_empty()
21    }
22
23    /// Returns an iterator over all tag-value pairs.
24    pub fn iter(&self) -> impl Iterator<Item = io::Result<(Tag, Value<'_>)>> + '_ {
25        let mut src = self.0;
26
27        iter::from_fn(move || {
28            if src.is_empty() {
29                None
30            } else {
31                Some(parse_field(&mut src))
32            }
33        })
34    }
35}
36
37impl fmt::Debug for Data<'_> {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        let mut formatter = f.debug_map();
40
41        for result in self.iter() {
42            let (tag, value) = result.map_err(|_| fmt::Error)?;
43            formatter.entry(&tag, &value);
44        }
45
46        formatter.finish()
47    }
48}
49
50impl crate::alignment::record::Data for Data<'_> {
51    fn is_empty(&self) -> bool {
52        self.is_empty()
53    }
54
55    fn get(&self, tag: &Tag) -> Option<io::Result<Value<'_>>> {
56        for result in self.iter() {
57            match result {
58                Ok((t, value)) => {
59                    if &t == tag {
60                        return Some(Ok(value));
61                    }
62                }
63                Err(e) => return Some(Err(e)),
64            }
65        }
66
67        None
68    }
69
70    fn iter(&self) -> Box<dyn Iterator<Item = io::Result<(Tag, Value<'_>)>> + '_> {
71        Box::new(self.iter())
72    }
73}
74
75impl AsRef<[u8]> for Data<'_> {
76    fn as_ref(&self) -> &[u8] {
77        self.0
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_iter() -> io::Result<()> {
87        let data = Data::new(b"");
88        assert!(data.iter().next().is_none());
89
90        let data = Data::new(b"NH:i:1");
91        let actual: Vec<_> = data.iter().collect::<io::Result<_>>()?;
92
93        assert_eq!(actual.len(), 1);
94
95        let (actual_tag, actual_value) = &actual[0];
96        assert_eq!(actual_tag, &Tag::ALIGNMENT_HIT_COUNT);
97        assert!(matches!(actual_value, Value::Int32(1)));
98
99        Ok(())
100    }
101}