1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
mod field;

use std::{io, iter};

use self::field::parse_field;
use crate::{variant::record::info::field::Value, Header};

/// Raw VCF record info.
#[derive(Debug, Eq, PartialEq)]
pub struct Info<'r>(&'r str);

impl<'r> Info<'r> {
    pub(super) fn new(buf: &'r str) -> Self {
        Self(buf)
    }

    /// Returns the value with the given key.
    pub fn get<'h: 'r>(
        &'r self,
        header: &'h Header,
        key: &str,
    ) -> Option<io::Result<Option<Value<'r>>>> {
        for result in self.iter(header) {
            match result {
                Ok((k, v)) => {
                    if k == key {
                        return Some(Ok(v));
                    }
                }
                Err(e) => return Some(Err(e)),
            }
        }

        None
    }

    /// Returns an iterator over all fields.
    pub fn iter<'h: 'r>(
        &'r self,
        header: &'h Header,
    ) -> impl Iterator<Item = io::Result<(&'r str, Option<Value<'r>>)>> + 'r {
        let mut src = self.0;

        iter::from_fn(move || {
            if src.is_empty() {
                None
            } else {
                Some(parse_field(&mut src, header))
            }
        })
    }
}

impl<'r> AsRef<str> for Info<'r> {
    fn as_ref(&self) -> &str {
        self.0
    }
}

impl<'r> crate::variant::record::Info for Info<'r> {
    fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    fn len(&self) -> usize {
        const DELIMITER: u8 = b';';

        if self.is_empty() {
            0
        } else {
            let n = self
                .0
                .as_bytes()
                .iter()
                .filter(|&&b| b == DELIMITER)
                .count();

            n + 1
        }
    }

    fn get<'a, 'h: 'a>(
        &'a self,
        header: &'h Header,
        key: &str,
    ) -> Option<io::Result<Option<Value<'a>>>> {
        self.get(header, key)
    }

    fn iter<'a, 'h: 'a>(
        &'a self,
        header: &'h Header,
    ) -> Box<dyn Iterator<Item = io::Result<(&'a str, Option<Value<'a>>)>> + 'a> {
        Box::new(self.iter(header))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::variant::record::Info as _;

    #[test]
    fn test_is_empty() {
        assert!(Info::new("").is_empty());
        assert!(!Info::new("NS=2;DP=.").is_empty());
    }

    #[test]
    fn test_iter() {
        use crate::variant::record::info::field::key;

        let header = Header::default();

        let info = Info::new("");
        assert!(info.iter(&header).next().is_none());

        let info = Info::new("NS=2;DP=.");
        let mut iter = info.iter(&header);

        assert!(matches!(
            iter.next(),
            Some(Ok((key::SAMPLES_WITH_DATA_COUNT, Some(Value::Integer(2)))))
        ));

        assert!(matches!(iter.next(), Some(Ok((key::TOTAL_DEPTH, None)))));
    }
}