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}