noodles_vcf/record/
info.rs1mod field;
2
3use std::{io, iter};
4
5use self::field::parse_field;
6use crate::{variant::record::info::field::Value, Header};
7
8#[derive(Debug, Eq, PartialEq)]
10pub struct Info<'r>(&'r str);
11
12impl<'r> Info<'r> {
13 pub(super) fn new(buf: &'r str) -> Self {
14 Self(buf)
15 }
16
17 pub fn get<'h: 'r>(
19 &'r self,
20 header: &'h Header,
21 key: &str,
22 ) -> Option<io::Result<Option<Value<'r>>>> {
23 for result in self.iter(header) {
24 match result {
25 Ok((k, v)) => {
26 if k == key {
27 return Some(Ok(v));
28 }
29 }
30 Err(e) => return Some(Err(e)),
31 }
32 }
33
34 None
35 }
36
37 pub fn iter<'h: 'r>(
39 &'r self,
40 header: &'h Header,
41 ) -> impl Iterator<Item = io::Result<(&'r str, Option<Value<'r>>)>> + 'r {
42 let mut src = self.0;
43
44 iter::from_fn(move || {
45 if src.is_empty() {
46 None
47 } else {
48 Some(parse_field(&mut src, header))
49 }
50 })
51 }
52}
53
54impl AsRef<str> for Info<'_> {
55 fn as_ref(&self) -> &str {
56 self.0
57 }
58}
59
60impl crate::variant::record::Info for Info<'_> {
61 fn is_empty(&self) -> bool {
62 self.0.is_empty()
63 }
64
65 fn len(&self) -> usize {
66 const DELIMITER: u8 = b';';
67
68 if self.is_empty() {
69 0
70 } else {
71 let n = self
72 .0
73 .as_bytes()
74 .iter()
75 .filter(|&&b| b == DELIMITER)
76 .count();
77
78 n + 1
79 }
80 }
81
82 fn get<'a, 'h: 'a>(
83 &'a self,
84 header: &'h Header,
85 key: &str,
86 ) -> Option<io::Result<Option<Value<'a>>>> {
87 self.get(header, key)
88 }
89
90 fn iter<'a, 'h: 'a>(
91 &'a self,
92 header: &'h Header,
93 ) -> Box<dyn Iterator<Item = io::Result<(&'a str, Option<Value<'a>>)>> + 'a> {
94 Box::new(self.iter(header))
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::variant::record::Info as _;
102
103 #[test]
104 fn test_is_empty() {
105 assert!(Info::new("").is_empty());
106 assert!(!Info::new("NS=2;DP=.").is_empty());
107 }
108
109 #[test]
110 fn test_iter() {
111 use crate::variant::record::info::field::key;
112
113 let header = Header::default();
114
115 let info = Info::new("");
116 assert!(info.iter(&header).next().is_none());
117
118 let info = Info::new("NS=2;DP=.");
119 let mut iter = info.iter(&header);
120
121 assert!(matches!(
122 iter.next(),
123 Some(Ok((key::SAMPLES_WITH_DATA_COUNT, Some(Value::Integer(2)))))
124 ));
125
126 assert!(matches!(iter.next(), Some(Ok((key::TOTAL_DEPTH, None)))));
127 }
128}