noodles_sam/record/
data.rs1pub mod field;
4
5use std::{borrow::Borrow, fmt, io, iter};
6
7use self::field::parse_field;
8use crate::alignment::record::data::field::{Tag, Value};
9
10pub 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 pub fn is_empty(&self) -> bool {
20 self.0.is_empty()
21 }
22
23 pub fn get<K>(&self, tag: &K) -> Option<io::Result<Value<'_>>>
25 where
26 K: Borrow<[u8; 2]>,
27 {
28 for result in self.iter() {
29 match result {
30 Ok((t, value)) => {
31 if &t == tag.borrow() {
32 return Some(Ok(value));
33 }
34 }
35 Err(e) => return Some(Err(e)),
36 }
37 }
38
39 None
40 }
41
42 pub fn iter(&self) -> impl Iterator<Item = io::Result<(Tag, Value<'_>)>> + '_ {
44 let mut src = self.0;
45
46 iter::from_fn(move || {
47 if src.is_empty() {
48 None
49 } else {
50 Some(parse_field(&mut src))
51 }
52 })
53 }
54}
55
56impl fmt::Debug for Data<'_> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 let mut formatter = f.debug_map();
59
60 for result in self.iter() {
61 let (tag, value) = result.map_err(|_| fmt::Error)?;
62 formatter.entry(&tag, &value);
63 }
64
65 formatter.finish()
66 }
67}
68
69impl crate::alignment::record::Data for Data<'_> {
70 fn is_empty(&self) -> bool {
71 self.is_empty()
72 }
73
74 fn get(&self, tag: &Tag) -> Option<io::Result<Value<'_>>> {
75 self.get(tag)
76 }
77
78 fn iter(&self) -> Box<dyn Iterator<Item = io::Result<(Tag, Value<'_>)>> + '_> {
79 Box::new(self.iter())
80 }
81}
82
83impl AsRef<[u8]> for Data<'_> {
84 fn as_ref(&self) -> &[u8] {
85 self.0
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_is_empty() {
95 let data = Data::new(b"");
96 assert!(data.is_empty());
97
98 let data = Data::new(b"NH:i:1");
99 assert!(!data.is_empty());
100 }
101
102 #[test]
103 fn test_get() -> io::Result<()> {
104 let data = Data::new(b"");
105 assert!(data.get(&Tag::ALIGNMENT_HIT_COUNT).is_none());
106 assert!(data.get(&Tag::COMMENT).is_none());
107
108 let data = Data::new(b"NH:i:1");
109 assert!(matches!(
110 data.get(&Tag::ALIGNMENT_HIT_COUNT).transpose()?,
111 Some(Value::Int32(1))
112 ));
113 assert!(data.get(&Tag::COMMENT).is_none());
114
115 let data = Data::new(b"NH:i:1\tCO:Z:ndls");
116 assert!(matches!(
117 data.get(&Tag::ALIGNMENT_HIT_COUNT).transpose()?,
118 Some(Value::Int32(1))
119 ));
120 assert!(matches!(
121 data.get(&Tag::COMMENT).transpose()?,
122 Some(Value::String(s)) if s == b"ndls"
123 ));
124
125 Ok(())
126 }
127
128 #[test]
129 fn test_iter() -> io::Result<()> {
130 let data = Data::new(b"");
131 assert!(data.iter().next().is_none());
132
133 let data = Data::new(b"NH:i:1");
134 let actual: Vec<_> = data.iter().collect::<io::Result<_>>()?;
135
136 assert_eq!(actual.len(), 1);
137
138 let (actual_tag, actual_value) = &actual[0];
139 assert_eq!(actual_tag, &Tag::ALIGNMENT_HIT_COUNT);
140 assert!(matches!(actual_value, Value::Int32(1)));
141
142 Ok(())
143 }
144}