brokaw/types/response/
capabilities.rs1use std::collections::{hash_map, HashMap, HashSet};
2use std::convert::TryFrom;
3use std::fmt;
4
5use crate::error::{Error, Result};
6use crate::types::prelude::*;
7use crate::types::response::util::err_if_not_kind;
8
9#[derive(Clone, Debug, Eq, PartialEq)]
11pub struct Capabilities(HashMap<String, Capability>);
12
13#[derive(Clone, Debug, Eq, PartialEq)]
15pub struct Capability {
16 pub name: String,
17 pub args: Option<HashSet<String>>,
18}
19
20impl Capabilities {
21 pub fn iter(&self) -> Iter<'_> {
23 Iter {
24 inner: self.0.values(),
25 }
26 }
27
28 pub fn get(&self, key: impl AsRef<str>) -> Option<&Capability> {
30 self.0.get(key.as_ref())
31 }
32}
33
34impl fmt::Display for Capability {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 write!(f, "{}", self.name)?;
37 if let Some(args) = self.args.as_ref() {
38 args.iter()
39 .map(|arg| {
40 write!(f, " {}", arg)?;
41 Ok::<_, fmt::Error>(())
42 })
43 .for_each(drop);
44 }
45
46 Ok(())
47 }
48}
49
50#[derive(Clone, Debug)]
52pub struct Iter<'a> {
53 inner: hash_map::Values<'a, String, Capability>,
54}
55
56impl<'a> Iterator for Iter<'a> {
57 type Item = &'a Capability;
58
59 fn next(&mut self) -> Option<Self::Item> {
60 self.inner.next()
61 }
62}
63
64impl TryFrom<&RawResponse> for Capabilities {
65 type Error = Error;
66
67 fn try_from(resp: &RawResponse) -> Result<Self> {
71 err_if_not_kind(resp, Kind::Capabilities)?;
72
73 let db_iter = resp
74 .data_blocks
75 .as_ref()
76 .ok_or_else(|| Error::de("Missing data blocks."))
77 .map(DataBlocks::unterminated)?;
78
79 let capabilities: HashMap<String, Capability> = db_iter
80 .map(String::from_utf8_lossy)
81 .map(|entry| {
82 let mut entry_iter = entry.split_whitespace().peekable();
83 let label = entry_iter
84 .next()
85 .map(ToString::to_string)
86 .ok_or_else(|| Error::de("Entry does not have a label"))?;
87
88 let args = if entry_iter.peek().is_some() {
89 Some(entry_iter.map(ToString::to_string).collect::<HashSet<_>>())
90 } else {
91 None
92 };
93
94 let cap = Capability {
95 name: label.clone(),
96 args,
97 };
98
99 Ok((label, cap))
100 })
101 .collect::<Result<_>>()?;
102
103 Ok(Self(capabilities))
104 }
105}