1use crate::errors::ParserError;
2use crate::prefix::Prefix;
3use crate::tokenizer::Tokenizer;
4use std::collections::HashMap;
5use std::convert::TryFrom;
6
7#[derive(Debug, Clone, Eq, PartialEq, Default)]
15pub struct Parsed<'a> {
16 tags: HashMap<&'a str, &'a str>,
17 prefix: Option<Prefix<'a>>,
18 command: Option<&'a str>,
19 params: Vec<Option<&'a str>>,
20 trailing: Option<&'a str>,
21}
22
23impl<'a> Parsed<'a> {
24 pub(crate) fn new(
25 tags: HashMap<&'a str, &'a str>,
26 prefix: Option<Prefix<'a>>,
27 command: Option<&'a str>,
28 params: Vec<Option<&'a str>>,
29 trailing: Option<&'a str>,
30 ) -> Self {
31 Self {
32 tags,
33 prefix,
34 command,
35 params,
36 trailing,
37 }
38 }
39
40 pub fn command(&self) -> Option<&'a str> {
41 self.command
42 }
43
44 pub fn prefix(&self) -> Option<&Prefix<'a>> {
45 self.prefix.as_ref()
46 }
47
48 pub fn params(&self) -> impl Iterator<Item = &Option<&'a str>> {
49 self.params.iter()
50 }
51
52 pub fn tags(&self) -> impl Iterator<Item = (&&'a str, &&'a str)> {
53 self.tags.iter()
54 }
55
56 pub fn tag(&self, key: &str) -> Option<&'a str> {
57 self.tags.get(key).copied()
58 }
59
60 pub fn param(&self, index: usize) -> Option<&'a str> {
90 match self.params.get(index) {
91 Some(Some(st)) => Some(*st),
92 _ => None,
93 }
94 }
95
96 pub fn trailing(&self) -> Option<&'a str> {
97 self.trailing
98 }
99
100 pub fn prefix_name(&self) -> Option<&'a str> {
101 self.prefix.as_ref().map(|&(name, _user, _host)| name)
102 }
103
104 pub fn prefix_user(&self) -> Option<&'a str> {
105 self.prefix.as_ref().and_then(|&(_name, user, _host)| user)
106 }
107
108 pub fn prefix_host(&self) -> Option<&'a str> {
109 self.prefix.as_ref().and_then(|&(_name, _user, host)| host)
110 }
111}
112
113impl<'a> TryFrom<&'a str> for Parsed<'a> {
114 type Error = ParserError;
115
116 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
117 let mut tokenizer = Tokenizer::new(value)?.tags();
118 let iter = tokenizer.as_iter();
119 let mut tags = HashMap::new();
120 for res in iter {
121 let (key, value) = res?;
122 tags.insert(key, value);
123 }
124 let mut tokenizer = tokenizer.prefix();
125 let prefix = tokenizer
126 .parts()?
127 .map(|(name, user, host)| (name, user, host));
128 let mut tokenizer = tokenizer.command();
129 let command = tokenizer.command()?;
130 let mut tokenizer = tokenizer.params();
131 let params = tokenizer.as_iter().map(Some).collect::<Vec<_>>();
132 let trailing = tokenizer.trailing().trailing();
133
134 Ok(Self {
135 tags,
136 prefix,
137 command: Some(command),
138 params,
139 trailing,
140 })
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::Message;
147 use std::error::Error;
148
149 #[test]
150 fn test_parsed() -> Result<(), Box<dyn Error>> {
151 let message = Message::builder("CMD")
152 .tag("tag1", "value1")
153 .tag("tag2", "value2")
154 .prefix("name", Some("user"), Some("host"))
155 .param("param0")
156 .trailing("Trailing Parameter!")
157 .build();
158 let parsed = message.parse()?;
159
160 assert_eq!(Some("value1"), parsed.tag("tag1"));
161 assert_eq!(Some("value2"), parsed.tag("tag2"));
162 assert_eq!(
163 Some(("name", Some("user"), Some("host"))),
164 parsed.prefix().map(|prefix| (prefix.0, prefix.1, prefix.2))
165 );
166 assert_eq!(Some("param0"), parsed.param(0));
167 assert_eq!(Some("Trailing Parameter!"), parsed.trailing());
168
169 Ok(())
170 }
171}