noodles_vcf/variant/record_buf/info.rs
1//! Variant record info fields.
2
3pub mod field;
4
5use std::{hash::Hash, io};
6
7use indexmap::IndexMap;
8
9use self::field::Value;
10use crate::Header;
11
12/// A variant record record info fields buffer.
13#[derive(Clone, Debug, Default, PartialEq)]
14pub struct Info(IndexMap<String, Option<Value>>);
15
16impl Info {
17 /// Removes all fields from the info map.
18 ///
19 /// This does not affect the capacity of the map.
20 ///
21 /// # Examples
22 ///
23 /// ```
24 /// use noodles_vcf::variant::{
25 /// record::{info::field::key, Info as _},
26 /// record_buf::{info::field::Value, Info},
27 /// };
28 ///
29 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
30 /// let dp = (String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
31 /// let mut info: Info = [ns, dp].into_iter().collect();
32 /// assert!(!info.is_empty());
33 ///
34 /// info.clear();
35 /// assert!(info.is_empty());
36 /// ```
37 pub fn clear(&mut self) {
38 self.0.clear();
39 }
40
41 /// Returns a reference to the field value with the given key.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use noodles_vcf::variant::{
47 /// record::info::field::key,
48 /// record_buf::{info::field::Value, Info},
49 /// };
50 ///
51 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
52 /// let dp = (String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
53 /// let info: Info = [ns, dp.clone()].into_iter().collect();
54 ///
55 /// assert_eq!(info.get(key::TOTAL_DEPTH), Some(Some(&Value::Integer(13))));
56 /// assert!(info.get(key::ALLELE_FREQUENCIES).is_none());
57 /// ```
58 pub fn get<K>(&self, key: &K) -> Option<Option<&Value>>
59 where
60 K: Hash + indexmap::Equivalent<String> + ?Sized,
61 {
62 self.0.get(key).map(|value| value.as_ref())
63 }
64
65 /// Returns a mutable reference to the field value with the given key.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// use noodles_vcf::variant::{
71 /// record::info::field::key,
72 /// record_buf::{info::field::Value, Info},
73 /// };
74 ///
75 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
76 /// let dp = (String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
77 /// let mut info: Info = [ns, dp].into_iter().collect();
78 ///
79 /// if let Some(value) = info.get_mut(key::TOTAL_DEPTH) {
80 /// *value = Some(Value::Integer(8));
81 /// }
82 ///
83 /// assert_eq!(info.get(key::TOTAL_DEPTH), Some(Some(&Value::Integer(8))));
84 /// ```
85 pub fn get_mut<K>(&mut self, key: &K) -> Option<&mut Option<Value>>
86 where
87 K: Hash + indexmap::Equivalent<String> + ?Sized,
88 {
89 self.0.get_mut(key)
90 }
91
92 /// Returns a reference to the field at the given index.
93 ///
94 /// # Examples
95 ///
96 /// ```
97 /// use noodles_vcf::variant::{
98 /// record::info::field::key,
99 /// record_buf::{info::field::Value, Info},
100 /// };
101 ///
102 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
103 /// let dp = (String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
104 /// let info: Info = [ns, dp].into_iter().collect();
105 ///
106 /// assert_eq!(
107 /// info.get_index(1),
108 /// Some((&String::from(key::TOTAL_DEPTH), Some(&Value::Integer(13))))
109 /// );
110 ///
111 /// assert!(info.get_index(5).is_none());
112 /// ```
113 pub fn get_index(&self, i: usize) -> Option<(&String, Option<&Value>)> {
114 self.0
115 .get_index(i)
116 .map(|(key, value)| (key, value.as_ref()))
117 }
118
119 /// Returns a mutable reference to the field at the given index.
120 ///
121 /// # Examples
122 ///
123 /// ```
124 /// use noodles_vcf::variant::{
125 /// record::info::field::key,
126 /// record_buf::{info::field::Value, Info},
127 /// };
128 ///
129 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
130 /// let dp = (String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
131 /// let mut info: Info = [ns, dp].into_iter().collect();
132 ///
133 /// if let Some((_, value)) = info.get_index_mut(1) {
134 /// *value = Some(Value::Integer(8));
135 /// }
136 ///
137 /// assert_eq!(
138 /// info.get_index(1),
139 /// Some((&String::from(key::TOTAL_DEPTH), Some(&Value::Integer(8))))
140 /// );
141 /// ```
142 pub fn get_index_mut(&mut self, i: usize) -> Option<(&String, &mut Option<Value>)> {
143 self.0.get_index_mut(i)
144 }
145
146 /// Inserts a field into the info map.
147 ///
148 /// If the key already exists in the map, the existing value is replaced by the new one, and
149 /// the existing value is returned.
150 ///
151 /// # Examples
152 ///
153 /// ```
154 /// use noodles_vcf::variant::{
155 /// record::{info::field::key, Info as _},
156 /// record_buf::{info::field::Value, Info},
157 /// };
158 ///
159 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
160 /// let mut info: Info = [ns].into_iter().collect();
161 /// assert_eq!(info.len(), 1);
162 ///
163 /// info.insert(String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
164 ///
165 /// assert_eq!(info.len(), 2);
166 /// assert_eq!(info.get(key::TOTAL_DEPTH), Some(Some(&Value::Integer(13))));
167 /// ```
168 pub fn insert(&mut self, key: String, value: Option<Value>) -> Option<Option<Value>> {
169 self.0.insert(key, value)
170 }
171
172 /// Returns an iterator over all keys.
173 ///
174 /// # Examples
175 ///
176 /// ```
177 /// use noodles_vcf::variant::{
178 /// record::info::field::key,
179 /// record_buf::{info::field::Value, Info},
180 /// };
181 ///
182 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
183 /// let dp = (String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
184 /// let info: Info = [ns, dp].into_iter().collect();
185 ///
186 /// let mut keys = info.keys();
187 ///
188 /// assert_eq!(keys.next(), Some(&String::from(key::SAMPLES_WITH_DATA_COUNT)));
189 /// assert_eq!(keys.next(), Some(&String::from(key::TOTAL_DEPTH)));
190 /// assert!(keys.next().is_none());
191 /// ```
192 pub fn keys(&self) -> impl Iterator<Item = &String> {
193 self.0.keys()
194 }
195
196 /// Returns an iterator over all values.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// use noodles_vcf::variant::{
202 /// record::info::field::key,
203 /// record_buf::{info::field::Value, Info},
204 /// };
205 ///
206 /// let ns = (String::from(key::SAMPLES_WITH_DATA_COUNT), Some(Value::Integer(2)));
207 /// let dp = (String::from(key::TOTAL_DEPTH), Some(Value::Integer(13)));
208 /// let info: Info = [ns, dp].into_iter().collect();
209 ///
210 /// let mut values = info.values();
211 ///
212 /// assert_eq!(values.next(), Some(Some(&Value::Integer(2))));
213 /// assert_eq!(values.next(), Some(Some(&Value::Integer(13))));
214 /// assert!(values.next().is_none());
215 /// ```
216 pub fn values(&self) -> impl Iterator<Item = Option<&Value>> {
217 self.0.values().map(|value| value.as_ref())
218 }
219}
220
221impl AsRef<IndexMap<String, Option<Value>>> for Info {
222 fn as_ref(&self) -> &IndexMap<String, Option<Value>> {
223 &self.0
224 }
225}
226
227impl AsMut<IndexMap<String, Option<Value>>> for Info {
228 fn as_mut(&mut self) -> &mut IndexMap<String, Option<Value>> {
229 &mut self.0
230 }
231}
232
233impl Extend<(String, Option<Value>)> for Info {
234 fn extend<T: IntoIterator<Item = (String, Option<Value>)>>(&mut self, iter: T) {
235 self.0.extend(iter);
236 }
237}
238
239impl FromIterator<(String, Option<Value>)> for Info {
240 fn from_iter<T: IntoIterator<Item = (String, Option<Value>)>>(iter: T) -> Self {
241 let mut info = Self::default();
242 info.extend(iter);
243 info
244 }
245}
246
247impl crate::variant::record::Info for Info {
248 fn is_empty(&self) -> bool {
249 self.0.is_empty()
250 }
251
252 fn len(&self) -> usize {
253 self.0.len()
254 }
255
256 fn get<'a, 'h: 'a>(
257 &'a self,
258 header: &'h Header,
259 key: &str,
260 ) -> Option<io::Result<Option<crate::variant::record::info::field::Value<'a>>>> {
261 for result in self.iter(header) {
262 match result {
263 Ok((k, value)) => {
264 if k == key {
265 return Some(Ok(value));
266 }
267 }
268 Err(e) => return Some(Err(e)),
269 }
270 }
271
272 None
273 }
274
275 fn iter<'a, 'h: 'a>(
276 &'a self,
277 _: &'h Header,
278 ) -> Box<
279 dyn Iterator<
280 Item = io::Result<(
281 &'a str,
282 Option<crate::variant::record::info::field::Value<'a>>,
283 )>,
284 > + 'a,
285 > {
286 Box::new(
287 self.0
288 .iter()
289 .map(|(key, value)| Ok((key.as_ref(), value.as_ref().map(|v| v.into())))),
290 )
291 }
292}
293
294impl crate::variant::record::Info for &Info {
295 fn is_empty(&self) -> bool {
296 self.0.is_empty()
297 }
298
299 fn len(&self) -> usize {
300 self.0.len()
301 }
302
303 fn get<'a, 'h: 'a>(
304 &'a self,
305 header: &'h Header,
306 key: &str,
307 ) -> Option<io::Result<Option<crate::variant::record::info::field::Value<'a>>>> {
308 crate::variant::record::Info::get(*self, header, key)
309 }
310
311 fn iter<'a, 'h: 'a>(
312 &'a self,
313 _: &'h Header,
314 ) -> Box<
315 dyn Iterator<
316 Item = io::Result<(
317 &'a str,
318 Option<crate::variant::record::info::field::Value<'a>>,
319 )>,
320 > + 'a,
321 > {
322 Box::new(
323 self.0
324 .iter()
325 .map(|(key, value)| Ok((key.as_ref(), value.as_ref().map(|v| v.into())))),
326 )
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333 use crate::variant::record::info::field::key;
334
335 #[test]
336 fn test_extend() {
337 let mut info = Info::default();
338
339 let fields = [(
340 String::from(key::SAMPLES_WITH_DATA_COUNT),
341 Some(Value::from(2)),
342 )];
343 info.extend(fields);
344
345 let expected = [(
346 String::from(key::SAMPLES_WITH_DATA_COUNT),
347 Some(Value::from(2)),
348 )]
349 .into_iter()
350 .collect();
351
352 assert_eq!(info, expected);
353 }
354}