1use crate::errors::ParserError;
2use crate::parsed::Parsed;
3use crate::Message;
4use std::collections::HashMap;
5use std::convert::TryFrom;
6use std::str::FromStr;
7
8#[derive(Debug, Clone, Eq, PartialEq, Default)]
62pub struct Builder {
63 tags: HashMap<String, String>,
64 prefix_name: Option<String>,
65 prefix_user: Option<String>,
66 prefix_host: Option<String>,
67 command: String,
68 params: Vec<String>,
69 trailing: Option<String>,
70}
71
72impl Builder {
73 pub fn new<S: ToString>(command: S) -> Self {
86 Builder {
87 tags: HashMap::new(),
88 prefix_name: None,
89 prefix_user: None,
90 prefix_host: None,
91 command: "".to_string(),
92 params: Vec::new(),
93 trailing: None,
94 }
95 .command(command.to_string())
96 }
97
98 pub fn command<S: ToString>(mut self, cmd: S) -> Builder {
104 let cmd = cmd.to_string();
105 if cmd.is_empty() {
106 panic!("tried to set empty command");
107 }
108 self.command = cmd;
109 self
110 }
111
112 pub fn tag<SK: ToString, SV: ToString>(mut self, key: SK, value: SV) -> Builder {
118 let key = key.to_string();
119 if key.is_empty() {
120 panic!("tried to set tag with empty key");
121 }
122 self.tags.insert(key, value.to_string());
123 self
124 }
125
126 pub fn prefix<SN, SU, SH>(mut self, name: SN, user: Option<SU>, host: Option<SH>) -> Builder
132 where
133 SN: ToString,
134 SU: ToString,
135 SH: ToString,
136 {
137 let name = name.to_string();
138 if name.is_empty() {
139 panic!("tried to set empty prefix name");
140 }
141 let user = user.map(|user| user.to_string());
142 if user.is_some() && user.as_ref().unwrap().is_empty() {
143 panic!("tried to set empty prefix user");
144 }
145 let host = host.map(|host| host.to_string());
146 if host.is_some() && host.as_ref().unwrap().is_empty() {
147 panic!("tried to set empty prefix host");
148 }
149 if user.is_some() && host.is_none() {
150 panic!("tried to set prefix user without host");
151 }
152 self.prefix_name = Some(name);
153 self.prefix_user = user;
154 self.prefix_host = host;
155 self
156 }
157
158 pub fn param<S: ToString>(mut self, param: S) -> Builder {
164 let param = param.to_string();
165 if param.is_empty() {
166 panic!("tried to add empty param");
167 }
168 self.params.push(param);
169 self
170 }
171
172 pub fn set_param<S: ToString>(mut self, index: usize, param: S) -> Builder {
180 let param = param.to_string();
181 if param.is_empty() {
182 panic!("tried to set empty param");
183 }
184 if index >= self.params.len() {
185 self.params.push(param);
186 } else {
187 self.params[index] = param;
188 }
189 self
190 }
191
192 pub fn remove_param(mut self, index: usize) -> Builder {
193 if index < self.params.len() {
194 self.params.remove(index);
195 }
196 self
197 }
198
199 pub fn trailing<S: ToString>(mut self, trailing: S) -> Builder {
201 self.trailing = Some(trailing.to_string());
202 self
203 }
204
205 pub fn build(self) -> crate::message::Message {
207 let mut str = String::new();
208 if !self.tags.is_empty() {
209 str.push('@');
210 for (key, val) in self.tags {
211 str.push_str(key.as_str());
212 str.push('=');
213 str.push_str(val.as_str());
214 str.push(';')
215 }
216 str.pop();
217 str.push(' ');
218 }
219 if let Some(prefix_name) = self.prefix_name {
220 str.push(':');
221 str.push_str(prefix_name.as_str());
222 assert!(self.prefix_user.is_none() || self.prefix_host.is_some());
224 if let Some(user) = self.prefix_user {
225 str.push('!');
226 str.push_str(user.as_str());
227 }
228 if let Some(host) = self.prefix_host {
229 str.push('@');
230 str.push_str(host.as_str());
231 }
232 str.push(' ')
233 }
234 str.push_str(self.command.as_str());
235 if !self.params.is_empty() {
236 str.push(' ');
237 str.push_str(&self.params.join(" "));
238 }
239 if let Some(trailing) = self.trailing {
240 str.push_str(" :");
241 str.push_str(trailing.as_str());
242 }
243 crate::message::Message::from(str)
244 }
245}
246
247impl FromStr for Builder {
248 type Err = ParserError;
249
250 fn from_str(s: &str) -> Result<Self, Self::Err> {
251 let parsed = Parsed::try_from(s)?;
252
253 let mut builder = Builder::new(parsed.command().ok_or(ParserError::NoCommand)?);
254 for (key, value) in parsed.tags() {
255 builder = builder.tag(key, value)
256 }
257 if let Some(&(name, user, host)) = parsed.prefix() {
258 builder = builder.prefix(name, user, host);
259 }
260 for param in parsed.params().flatten() {
262 builder = builder.param(param);
263 }
264 if let Some(trailing) = parsed.trailing() {
265 builder = builder.trailing(trailing);
266 }
267
268 Ok(builder)
269 }
270}
271
272impl TryFrom<Message> for Builder {
273 type Error = ParserError;
274
275 fn try_from(value: Message) -> Result<Self, Self::Error> {
276 value.to_builder()
277 }
278}