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
use super::prelude::*;

#[derive(Debug)]
pub struct qSupported<'a> {
    pub packet_buffer_len: usize,
    pub features: Features<'a>,
}

impl<'a> ParseCommand<'a> for qSupported<'a> {
    fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
        let packet_buffer_len = buf.full_len();

        let body = buf.into_body();
        if body.is_empty() {
            return None;
        }

        Some(qSupported {
            packet_buffer_len,
            features: Features(body),
        })
    }
}

#[derive(Debug)]
pub struct Features<'a>(&'a [u8]);

impl<'a> Features<'a> {
    pub fn into_iter(self) -> impl Iterator<Item = Option<Feature<'a>>> + 'a {
        self.0.split(|b| *b == b';').map(|s| match s.last() {
            None => None,
            Some(&c) if c == b'+' || c == b'-' || c == b'?' => Some(Feature {
                name: s[..s.len() - 1].into(),
                val: None,
                status: match c {
                    b'+' => FeatureSupported::Yes,
                    b'-' => FeatureSupported::No,
                    b'?' => FeatureSupported::Maybe,
                    _ => return None,
                },
            }),
            Some(_) => {
                let mut parts = s.split(|b| *b == b'=');
                Some(Feature {
                    name: parts.next()?.into(),
                    val: Some(parts.next()?.into()),
                    status: FeatureSupported::Yes,
                })
            }
        })
    }
}

#[derive(Debug)]
pub enum FeatureSupported {
    Yes,
    No,
    Maybe,
}

#[derive(Debug)]
pub struct Feature<'a> {
    name: Bstr<'a>,
    val: Option<Bstr<'a>>,
    status: FeatureSupported,
}