noodles_vcf/record/samples/
sample.rs1use std::{io, iter};
2
3use super::{series::value::parse_value, Keys};
4use crate::{variant::record::samples::series::Value, Header};
5
6#[derive(Debug, Eq, PartialEq)]
8pub struct Sample<'s> {
9 src: &'s str,
10 keys: Keys<'s>,
11}
12
13impl<'s> Sample<'s> {
14 pub(super) fn new(src: &'s str, keys: Keys<'s>) -> Self {
15 Self { src, keys }
16 }
17
18 pub fn get_index<'h: 's>(
20 &self,
21 header: &'h Header,
22 i: usize,
23 ) -> Option<Option<io::Result<Value<'s>>>> {
24 self.values(header).nth(i)
25 }
26
27 pub fn values<'h: 's>(
29 &self,
30 header: &'h Header,
31 ) -> impl Iterator<Item = Option<io::Result<Value<'s>>>> + '_ {
32 self.iter(header)
33 .map(|result| result.map(|(_, value)| value).transpose())
34 }
35
36 pub fn iter<'h: 's>(
38 &self,
39 header: &'h Header,
40 ) -> Box<dyn Iterator<Item = io::Result<(&str, Option<Value<'s>>)>> + '_> {
41 const DELIMITER: char = ':';
42
43 if self.as_ref().is_empty() {
44 Box::new(iter::empty())
45 } else {
46 Box::new(
47 self.keys
48 .iter()
49 .zip(self.src.split(DELIMITER))
50 .map(|(key, s)| parse_value(s, header, key).map(|value| (key, value))),
51 )
52 }
53 }
54}
55
56impl AsRef<str> for Sample<'_> {
57 fn as_ref(&self) -> &str {
58 self.src
59 }
60}
61
62impl crate::variant::record::samples::Sample for Sample<'_> {
63 fn get<'a, 'h: 'a>(
64 &'a self,
65 header: &'h Header,
66 key: &str,
67 ) -> Option<io::Result<Option<Value<'a>>>> {
68 for result in self.iter(header) {
69 match result {
70 Ok((k, v)) => {
71 if k == key {
72 return Some(Ok(v));
73 }
74 }
75 Err(e) => return Some(Err(e)),
76 }
77 }
78
79 None
80 }
81
82 fn get_index<'a, 'h: 'a>(
83 &'a self,
84 header: &'h Header,
85 i: usize,
86 ) -> Option<io::Result<Option<Value<'a>>>> {
87 self.iter(header)
88 .nth(i)
89 .map(|result| result.map(|(_, value)| value))
90 }
91
92 fn iter<'a, 'h: 'a>(
93 &'a self,
94 header: &'h Header,
95 ) -> Box<dyn Iterator<Item = io::Result<(&'a str, Option<Value<'a>>)>> + 'a> {
96 Box::new(self.iter(header))
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_values() {
106 let header = Header::default();
107
108 let keys = Keys::new("GT:GQ");
109 let sample = Sample::new("0|0:.", keys);
110 let mut iter = sample.values(&header);
111
112 assert!(matches!(iter.next(), Some(Some(Ok(Value::Genotype(_))))));
113 assert!(matches!(iter.next(), Some(None)));
114 assert!(iter.next().is_none());
115 }
116
117 #[test]
118 fn test_iter() {
119 let header = Header::default();
120
121 let keys = Keys::new("GT:GQ");
122 let sample = Sample::new("0|0:.", keys);
123 let mut iter = sample.iter(&header);
124
125 assert!(matches!(
126 iter.next(),
127 Some(Ok(("GT", Some(Value::Genotype(_)))))
128 ));
129
130 assert!(matches!(iter.next(), Some(Ok(("GQ", None)))));
131
132 assert!(iter.next().is_none());
133 }
134}